[PATCH v3 1/14] D: The front-end (DMD) language implementation and license.

Changes since previous are just merge latest 2.076 release.

---
diff --git a/gcc/d/dfrontend/aav.c b/gcc/d/dfrontend/aav.c
new file mode 100644
index 00000000000..5f5e6b3dd39
--- /dev/null
+++ b/gcc/d/dfrontend/aav.c
@@ -0,0 +1,193 @@
+
+/* Copyright (c) 2010-2014 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/aav.c
+ */
+
+/**
+ * Implementation of associative arrays.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "aav.h"
+#include "rmem.h"
+
+
+inline size_t hash(size_t a)
+{
+    a ^= (a >> 20) ^ (a >> 12);
+    return a ^ (a >> 7) ^ (a >> 4);
+}
+
+struct aaA
+{
+    aaA *next;
+    Key key;
+    Value value;
+};
+
+struct AA
+{
+    aaA* *b;
+    size_t b_length;
+    size_t nodes;       // total number of aaA nodes
+    aaA* binit[4];      // initial value of b[]
+
+    aaA aafirst;        // a lot of these AA's have only one entry
+};
+
+/****************************************************
+ * Determine number of entries in associative array.
+ */
+
+size_t dmd_aaLen(AA* aa)
+{
+    return aa ? aa->nodes : 0;
+}
+
+
+/*************************************************
+ * Get pointer to value in associative array indexed by key.
+ * Add entry for key if it is not already there, returning a pointer to a null Value.
+ * Create the associative array if it does not already exist.
+ */
+
+Value* dmd_aaGet(AA** paa, Key key)
+{
+    //printf("paa = %p\n", paa);
+
+    if (!*paa)
+    {   AA *a = (AA *)mem.xmalloc(sizeof(AA));
+        a->b = (aaA**)a->binit;
+        a->b_length = 4;
+        a->nodes = 0;
+        a->binit[0] = NULL;
+        a->binit[1] = NULL;
+        a->binit[2] = NULL;
+        a->binit[3] = NULL;
+        *paa = a;
+        assert((*paa)->b_length == 4);
+    }
+    //printf("paa = %p, *paa = %p\n", paa, *paa);
+
+    assert((*paa)->b_length);
+    size_t i = hash((size_t)key) & ((*paa)->b_length - 1);
+    aaA** pe = &(*paa)->b[i];
+    aaA *e;
+    while ((e = *pe) != NULL)
+    {
+        if (key == e->key)
+            return &e->value;
+        pe = &e->next;
+    }
+
+    // Not found, create new elem
+    //printf("create new one\n");
+
+    size_t nodes = ++(*paa)->nodes;
+    e = (nodes != 1) ? (aaA *)mem.xmalloc(sizeof(aaA)) : &(*paa)->aafirst;
+    //e = new aaA();
+    e->next = NULL;
+    e->key = key;
+    e->value = NULL;
+    *pe = e;
+
+    //printf("length = %d, nodes = %d\n", (*paa)->b_length, nodes);
+    if (nodes > (*paa)->b_length * 2)
+    {
+        //printf("rehash\n");
+        dmd_aaRehash(paa);
+    }
+
+    return &e->value;
+}
+
+
+/*************************************************
+ * Get value in associative array indexed by key.
+ * Returns NULL if it is not already there.
+ */
+
+Value dmd_aaGetRvalue(AA* aa, Key key)
+{
+    //printf("_aaGetRvalue(key = %p)\n", key);
+    if (aa)
+    {
+        size_t i;
+        size_t len = aa->b_length;
+        i = hash((size_t)key) & (len-1);
+        aaA* e = aa->b[i];
+        while (e)
+        {
+            if (key == e->key)
+                return e->value;
+            e = e->next;
+        }
+    }
+    return NULL;    // not found
+}
+
+
+/********************************************
+ * Rehash an array.
+ */
+
+void dmd_aaRehash(AA** paa)
+{
+    //printf("Rehash\n");
+    if (*paa)
+    {
+        AA *aa = *paa;
+        if (aa)
+        {
+            size_t len = aa->b_length;
+            if (len == 4)
+                len = 32;
+            else
+                len *= 4;
+            aaA** newb = (aaA**)mem.xmalloc(sizeof(aaA)*len);
+            memset(newb, 0, len * sizeof(aaA*));
+
+            for (size_t k = 0; k < aa->b_length; k++)
+            {   aaA *e = aa->b[k];
+                while (e)
+                {   aaA* enext = e->next;
+                    size_t j = hash((size_t)e->key) & (len-1);
+                    e->next = newb[j];
+                    newb[j] = e;
+                    e = enext;
+                }
+            }
+            if (aa->b != (aaA**)aa->binit)
+                mem.xfree(aa->b);
+
+            aa->b = newb;
+            aa->b_length = len;
+        }
+    }
+}
+
+
+#if UNITTEST
+
+void unittest_aa()
+{
+    AA* aa = NULL;
+    Value v = dmd_aaGetRvalue(aa, NULL);
+    assert(!v);
+    Value *pv = dmd_aaGet(&aa, NULL);
+    assert(pv);
+    *pv = (void *)3;
+    v = dmd_aaGetRvalue(aa, NULL);
+    assert(v == (void *)3);
+}
+
+#endif
diff --git a/gcc/d/dfrontend/aav.h b/gcc/d/dfrontend/aav.h
new file mode 100644
index 00000000000..d4182503412
--- /dev/null
+++ b/gcc/d/dfrontend/aav.h
@@ -0,0 +1,19 @@
+
+/* Copyright (c) 2010-2014 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/aav.h
+ */
+
+typedef void* Value;
+typedef void* Key;
+
+struct AA;
+
+size_t dmd_aaLen(AA* aa);
+Value* dmd_aaGet(AA** aa, Key key);
+Value dmd_aaGetRvalue(AA* aa, Key key);
+void dmd_aaRehash(AA** paa);
+
diff --git a/gcc/d/dfrontend/access.c b/gcc/d/dfrontend/access.c
new file mode 100644
index 00000000000..a80e677b079
--- /dev/null
+++ b/gcc/d/dfrontend/access.c
@@ -0,0 +1,670 @@
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/access.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "root.h"
+#include "rmem.h"
+
+#include "enum.h"
+#include "aggregate.h"
+#include "init.h"
+#include "attrib.h"
+#include "scope.h"
+#include "id.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "expression.h"
+#include "module.h"
+#include "template.h"
+
+#define LOG 0
+
+/* Code to do access checks
+ */
+
+bool hasPackageAccess(Scope *sc, Dsymbol *s);
+bool hasPackageAccess(Module *mod, Dsymbol *s);
+bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember);
+bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd);
+static Dsymbol *mostVisibleOverload(Dsymbol *s);
+
+/****************************************
+ * Return Prot access for Dsymbol smember in this declaration.
+ */
+Prot getAccess(AggregateDeclaration *ad, Dsymbol *smember)
+{
+    Prot access_ret = Prot(PROTnone);
+
+#if LOG
+    printf("+AggregateDeclaration::getAccess(this = '%s', smember = '%s')\n",
+        ad->toChars(), smember->toChars());
+#endif
+
+    assert(ad->isStructDeclaration() || ad->isClassDeclaration());
+    if (smember->toParent() == ad)
+    {
+        access_ret = smember->prot();
+    }
+    else if (smember->isDeclaration()->isStatic())
+    {
+        access_ret = smember->prot();
+    }
+    if (ClassDeclaration *cd = ad->isClassDeclaration())
+    {
+        for (size_t i = 0; i < cd->baseclasses->dim; i++)
+        {
+            BaseClass *b = (*cd->baseclasses)[i];
+
+            Prot access = getAccess(b->sym, smember);
+            switch (access.kind)
+            {
+                case PROTnone:
+                    break;
+
+                case PROTprivate:
+                    access_ret = Prot(PROTnone);  // private members of base class not accessible
+                    break;
+
+                case PROTpackage:
+                case PROTprotected:
+                case PROTpublic:
+                case PROTexport:
+                    // If access is to be tightened
+                    if (PROTpublic < access.kind)
+                        access = Prot(PROTpublic);
+
+                    // Pick path with loosest access
+                    if (access_ret.isMoreRestrictiveThan(access))
+                        access_ret = access;
+                    break;
+
+                default:
+                    assert(0);
+            }
+        }
+    }
+
+#if LOG
+    printf("-AggregateDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
+        ad->toChars(), smember->toChars(), access_ret);
+#endif
+    return access_ret;
+}
+
+/********************************************************
+ * Helper function for checkAccess()
+ * Returns:
+ *      false   is not accessible
+ *      true    is accessible
+ */
+static bool isAccessible(
+        Dsymbol *smember,
+        Dsymbol *sfunc,
+        AggregateDeclaration *dthis,
+        AggregateDeclaration *cdscope)
+{
+    assert(dthis);
+
+#if 0
+    printf("isAccessible for %s.%s in function %s() in scope %s\n",
+        dthis->toChars(), smember->toChars(),
+        sfunc ? sfunc->toChars() : "NULL",
+        cdscope ? cdscope->toChars() : "NULL");
+#endif
+    if (hasPrivateAccess(dthis, sfunc) ||
+        isFriendOf(dthis, cdscope))
+    {
+        if (smember->toParent() == dthis)
+            return true;
+
+        if (ClassDeclaration *cdthis = dthis->isClassDeclaration())
+        {
+            for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
+            {
+                BaseClass *b = (*cdthis->baseclasses)[i];
+                Prot access = getAccess(b->sym, smember);
+                if (access.kind >= PROTprotected ||
+                    isAccessible(smember, sfunc, b->sym, cdscope))
+                {
+                    return true;
+                }
+            }
+        }
+    }
+    else
+    {
+        if (smember->toParent() != dthis)
+        {
+            if (ClassDeclaration *cdthis = dthis->isClassDeclaration())
+            {
+                for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
+                {
+                    BaseClass *b = (*cdthis->baseclasses)[i];
+                    if (isAccessible(smember, sfunc, b->sym, cdscope))
+                        return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+/*******************************
+ * Do access check for member of this class, this class being the
+ * type of the 'this' pointer used to access smember.
+ * Returns true if the member is not accessible.
+ */
+bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember)
+{
+    FuncDeclaration *f = sc->func;
+    AggregateDeclaration *cdscope = sc->getStructClassScope();
+
+#if LOG
+    printf("AggregateDeclaration::checkAccess() for %s.%s in function %s() in scope %s\n",
+        ad->toChars(), smember->toChars(),
+        f ? f->toChars() : NULL,
+        cdscope ? cdscope->toChars() : NULL);
+#endif
+
+    Dsymbol *smemberparent = smember->toParent();
+    if (!smemberparent || !smemberparent->isAggregateDeclaration())
+    {
+#if LOG
+        printf("not an aggregate member\n");
+#endif
+        return false;                   // then it is accessible
+    }
+
+    // BUG: should enable this check
+    //assert(smember->parent->isBaseOf(this, NULL));
+
+    bool result;
+    Prot access;
+    if (smemberparent == ad)
+    {
+        access = smember->prot();
+        result = access.kind >= PROTpublic ||
+                 hasPrivateAccess(ad, f) ||
+                 isFriendOf(ad, cdscope) ||
+                 (access.kind == PROTpackage && hasPackageAccess(sc, smember)) ||
+                 ad->getAccessModule() == sc->_module;
+#if LOG
+        printf("result1 = %d\n", result);
+#endif
+    }
+    else if ((access = getAccess(ad, smember)).kind >= PROTpublic)
+    {
+        result = true;
+#if LOG
+        printf("result2 = %d\n", result);
+#endif
+    }
+    else if (access.kind == PROTpackage && hasPackageAccess(sc, ad))
+    {
+        result = true;
+#if LOG
+        printf("result3 = %d\n", result);
+#endif
+    }
+    else
+    {
+        result = isAccessible(smember, f, ad, cdscope);
+#if LOG
+        printf("result4 = %d\n", result);
+#endif
+    }
+    if (!result)
+    {
+        ad->error(loc, "member %s is not accessible", smember->toChars());
+        //printf("smember = %s %s, prot = %d, semanticRun = %d\n",
+        //        smember->kind(), smember->toPrettyChars(), smember->prot(), smember->semanticRun);
+        return true;
+    }
+    return false;
+}
+
+/****************************************
+ * Determine if this is the same or friend of cd.
+ */
+bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd)
+{
+#if LOG
+    printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", ad->toChars(), cd ? cd->toChars() : "null");
+#endif
+    if (ad == cd)
+        return true;
+
+    // Friends if both are in the same module
+    //if (toParent() == cd->toParent())
+    if (cd && ad->getAccessModule() == cd->getAccessModule())
+    {
+#if LOG
+        printf("\tin same module\n");
+#endif
+        return true;
+    }
+
+#if LOG
+    printf("\tnot friend\n");
+#endif
+    return false;
+}
+
+/****************************************
+ * Determine if scope sc has package level access to s.
+ */
+bool hasPackageAccess(Scope *sc, Dsymbol *s)
+{
+    return hasPackageAccess(sc->_module, s);
+}
+
+bool hasPackageAccess(Module *mod, Dsymbol *s)
+{
+#if LOG
+    printf("hasPackageAccess(s = '%s', mod = '%s', s->protection.pkg = '%s')\n",
+            s->toChars(), mod->toChars(),
+            s->prot().pkg ? s->prot().pkg->toChars() : "NULL");
+#endif
+
+    Package *pkg = NULL;
+
+    if (s->prot().pkg)
+        pkg = s->prot().pkg;
+    else
+    {
+        // no explicit package for protection, inferring most qualified one
+        for (; s; s = s->parent)
+        {
+            if (Module *m = s->isModule())
+            {
+                DsymbolTable *dst = Package::resolve(m->md ? m->md->packages : NULL, NULL, NULL);
+                assert(dst);
+                Dsymbol *s2 = dst->lookup(m->ident);
+                assert(s2);
+                Package *p = s2->isPackage();
+                if (p && p->isPackageMod())
+                {
+                    pkg = p;
+                    break;
+                }
+            }
+            else if ((pkg = s->isPackage()) != NULL)
+                break;
+        }
+    }
+#if LOG
+    if (pkg)
+        printf("\tsymbol access binds to package '%s'\n", pkg->toChars());
+#endif
+
+    if (pkg)
+    {
+        if (pkg == mod->parent)
+        {
+#if LOG
+            printf("\tsc is in permitted package for s\n");
+#endif
+            return true;
+        }
+        if (pkg->isPackageMod() == mod)
+        {
+#if LOG
+            printf("\ts is in same package.d module as sc\n");
+#endif
+            return true;
+        }
+        Dsymbol* ancestor = mod->parent;
+        for (; ancestor; ancestor = ancestor->parent)
+        {
+            if (ancestor == pkg)
+            {
+#if LOG
+                printf("\tsc is in permitted ancestor package for s\n");
+#endif
+                return true;
+            }
+        }
+    }
+
+#if LOG
+    printf("\tno package access\n");
+#endif
+    return false;
+}
+
+/****************************************
+ * Determine if scope sc has protected level access to cd.
+ */
+bool hasProtectedAccess(Scope *sc, Dsymbol *s)
+{
+    if (ClassDeclaration *cd = s->isClassMember()) // also includes interfaces
+    {
+        for (Scope *scx = sc; scx; scx = scx->enclosing)
+        {
+            if (!scx->scopesym)
+                continue;
+            ClassDeclaration *cd2 = scx->scopesym->isClassDeclaration();
+            if (cd2 && cd->isBaseOf(cd2, NULL))
+                return true;
+        }
+    }
+    return sc->_module == s->getAccessModule();
+}
+
+/**********************************
+ * Determine if smember has access to private members of this declaration.
+ */
+bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember)
+{
+    if (smember)
+    {
+        AggregateDeclaration *cd = NULL;
+        Dsymbol *smemberparent = smember->toParent();
+        if (smemberparent)
+            cd = smemberparent->isAggregateDeclaration();
+
+#if LOG
+        printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n",
+                ad->toChars(), smember->toChars());
+#endif
+
+        if (ad == cd)         // smember is a member of this class
+        {
+#if LOG
+            printf("\tyes 1\n");
+#endif
+            return true;           // so we get private access
+        }
+
+        // If both are members of the same module, grant access
+        while (1)
+        {
+            Dsymbol *sp = smember->toParent();
+            if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
+                smember = sp;
+            else
+                break;
+        }
+        if (!cd && ad->toParent() == smember->toParent())
+        {
+#if LOG
+            printf("\tyes 2\n");
+#endif
+            return true;
+        }
+        if (!cd && ad->getAccessModule() == smember->getAccessModule())
+        {
+#if LOG
+            printf("\tyes 3\n");
+#endif
+            return true;
+        }
+    }
+#if LOG
+    printf("\tno\n");
+#endif
+    return false;
+}
+
+/****************************************
+ * Check access to d for expression e.d
+ * Returns true if the declaration is not accessible.
+ */
+bool checkAccess(Loc loc, Scope *sc, Expression *e, Declaration *d)
+{
+    if (sc->flags & SCOPEnoaccesscheck)
+        return false;
+
+#if LOG
+    if (e)
+    {
+        printf("checkAccess(%s . %s)\n", e->toChars(), d->toChars());
+        printf("\te->type = %s\n", e->type->toChars());
+    }
+    else
+    {
+        printf("checkAccess(%s)\n", d->toPrettyChars());
+    }
+#endif
+    if (d->isUnitTestDeclaration())
+    {
+        // Unittests are always accessible.
+        return false;
+    }
+    if (!e)
+    {
+        if (d->prot().kind == PROTprivate && d->getAccessModule() != sc->_module ||
+            d->prot().kind == PROTpackage && !hasPackageAccess(sc, d))
+        {
+            error(loc, "%s %s is not accessible from module %s",
+                d->kind(), d->toPrettyChars(), sc->_module->toChars());
+            return true;
+        }
+    }
+    else if (e->type->ty == Tclass)
+    {
+        // Do access check
+        ClassDeclaration *cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
+        if (e->op == TOKsuper)
+        {
+            ClassDeclaration *cd2 = sc->func->toParent()->isClassDeclaration();
+            if (cd2)
+                cd = cd2;
+        }
+        return checkAccess(cd, loc, sc, d);
+    }
+    else if (e->type->ty == Tstruct)
+    {
+        // Do access check
+        StructDeclaration *cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
+        return checkAccess(cd, loc, sc, d);
+    }
+    return false;
+}
+
+/****************************************
+ * Check access to package/module `p` from scope `sc`.
+ *
+ * Params:
+ *   loc = source location for issued error message
+ *   sc = scope from which to access to a fully qualified package name
+ *   p = the package/module to check access for
+ * Returns: true if the package is not accessible.
+ *
+ * Because a global symbol table tree is used for imported packages/modules,
+ * access to them needs to be checked based on the imports in the scope chain
+ * (see Bugzilla 313).
+ *
+ */
+bool checkAccess(Loc loc, Scope *sc, Package *p)
+{
+    if (sc->_module == p)
+        return false;
+    for (; sc; sc = sc->enclosing)
+    {
+        if (sc->scopesym && sc->scopesym->isPackageAccessible(p, Prot(PROTprivate)))
+            return false;
+    }
+    const char *name = p->toPrettyChars();
+    if (p->isPkgMod == PKGmodule || p->isModule())
+        deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", p->kind(), name, name);
+    else
+        deprecation(loc, "%s %s is not accessible here", p->kind(), name);
+    return true;
+}
+
+/**
+ * Check whether symbols `s` is visible in `mod`.
+ *
+ * Params:
+ *  mod = lookup origin
+ *  s = symbol to check for visibility
+ * Returns: true if s is visible in mod
+ */
+bool symbolIsVisible(Module *mod, Dsymbol *s)
+{
+    // should sort overloads by ascending protection instead of iterating here
+    s = mostVisibleOverload(s);
+
+    switch (s->prot().kind)
+    {
+        case PROTundefined:
+            return true;
+        case PROTnone:
+            return false; // no access
+        case PROTprivate:
+            return s->getAccessModule() == mod;
+        case PROTpackage:
+            return hasPackageAccess(mod, s);
+        case PROTprotected:
+            return s->getAccessModule() == mod;
+        case PROTpublic:
+        case PROTexport:
+            return true;
+        default:
+            assert(0);
+    }
+}
+
+/**
+ * Same as above, but determines the lookup module from symbols `origin`.
+ */
+bool symbolIsVisible(Dsymbol *origin, Dsymbol *s)
+{
+    return symbolIsVisible(origin->getAccessModule(), s);
+}
+
+/**
+ * Same as above but also checks for protected symbols visible from scope `sc`.
+ * Used for qualified name lookup.
+ *
+ * Params:
+ *  sc = lookup scope
+ *  s = symbol to check for visibility
+ * Returns: true if s is visible by origin
+ */
+bool symbolIsVisible(Scope *sc, Dsymbol *s)
+{
+    s = mostVisibleOverload(s);
+
+    switch (s->prot().kind)
+    {
+        case PROTundefined:
+            return true;
+        case PROTnone:
+            return false; // no access
+        case PROTprivate:
+            return sc->_module == s->getAccessModule();
+        case PROTpackage:
+            return hasPackageAccess(sc->_module, s);
+        case PROTprotected:
+            return hasProtectedAccess(sc, s);
+        case PROTpublic:
+        case PROTexport:
+            return true;
+        default:
+            assert(0);
+    }
+}
+
+/**
+ * Use the most visible overload to check visibility. Later perform an access
+ * check on the resolved overload.  This function is similar to overloadApply,
+ * but doesn't recurse nor resolve aliases because protection/visibility is an
+ * attribute of the alias not the aliasee.
+ */
+static Dsymbol *mostVisibleOverload(Dsymbol *s)
+{
+    if (!s->isOverloadable())
+        return s;
+
+    Dsymbol *next = NULL;
+    Dsymbol *fstart = s;
+    Dsymbol *mostVisible = s;
+    for (; s; s = next)
+    {
+        // void func() {}
+        // private void func(int) {}
+        if (FuncDeclaration *fd = s->isFuncDeclaration())
+            next = fd->overnext;
+        // template temp(T) {}
+        // private template temp(T:int) {}
+        else if (TemplateDeclaration *td = s->isTemplateDeclaration())
+            next = td->overnext;
+        // alias common = mod1.func1;
+        // alias common = mod2.func2;
+        else if (FuncAliasDeclaration *fa = s->isFuncAliasDeclaration())
+            next = fa->overnext;
+        // alias common = mod1.templ1;
+        // alias common = mod2.templ2;
+        else if (OverDeclaration *od = s->isOverDeclaration())
+            next = od->overnext;
+        // alias name = sym;
+        // private void name(int) {}
+        else if (AliasDeclaration *ad = s->isAliasDeclaration())
+        {
+            if (!ad->isOverloadable())
+            {
+                //printf("Non overloadable Aliasee in overload list\n");
+                assert(0);
+            }
+            // Yet unresolved aliases store overloads in overnext.
+            if (ad->semanticRun < PASSsemanticdone)
+                next = ad->overnext;
+            else
+            {
+                /* This is a bit messy due to the complicated implementation of
+                 * alias.  Aliases aren't overloadable themselves, but if their
+                 * Aliasee is overloadable they can be converted to an overloadable
+                 * alias.
+                 *
+                 * This is done by replacing the Aliasee w/ FuncAliasDeclaration
+                 * (for functions) or OverDeclaration (for templates) which are
+                 * simply overloadable aliases w/ weird names.
+                 *
+                 * Usually aliases should not be resolved for visibility checking
+                 * b/c public aliases to private symbols are public. But for the
+                 * overloadable alias situation, the Alias (_ad_) has been moved
+                 * into it's own Aliasee, leaving a shell that we peel away here.
+                 */
+                Dsymbol *aliasee = ad->toAlias();
+                if (aliasee->isFuncAliasDeclaration() || aliasee->isOverDeclaration())
+                    next = aliasee;
+                else
+                {
+                    /* A simple alias can be at the end of a function or template overload chain.
+                     * It can't have further overloads b/c it would have been
+                     * converted to an overloadable alias.
+                     */
+                    if (ad->overnext)
+                    {
+                        //printf("Unresolved overload of alias\n");
+                        assert(0);
+                    }
+                    break;
+                }
+            }
+
+            // handled by overloadApply for unknown reason
+            assert(next != ad); // should not alias itself
+            assert(next != fstart); // should not alias the overload list itself
+        }
+        else
+            break;
+
+        if (next && mostVisible->prot().isMoreRestrictiveThan(next->prot()))
+            mostVisible = next;
+    }
+    return mostVisible;
+}
diff --git a/gcc/d/dfrontend/aggregate.h b/gcc/d/dfrontend/aggregate.h
new file mode 100644
index 00000000000..7bbde2e45f4
--- /dev/null
+++ b/gcc/d/dfrontend/aggregate.h
@@ -0,0 +1,342 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/aggregate.h
+ */
+
+#ifndef DMD_AGGREGATE_H
+#define DMD_AGGREGATE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+
+#include "dsymbol.h"
+#include "declaration.h"
+#include "objc.h"
+
+class Identifier;
+class Type;
+class TypeFunction;
+class Expression;
+class FuncDeclaration;
+class CtorDeclaration;
+class DtorDeclaration;
+class InvariantDeclaration;
+class NewDeclaration;
+class DeleteDeclaration;
+class InterfaceDeclaration;
+class TypeInfoClassDeclaration;
+class VarDeclaration;
+
+enum Sizeok
+{
+    SIZEOKnone,         // size of aggregate is not yet able to compute
+    SIZEOKfwd,          // size of aggregate is ready to compute
+    SIZEOKdone,         // size of aggregate is set correctly
+};
+
+enum Baseok
+{
+    BASEOKnone,         // base classes not computed yet
+    BASEOKin,           // in process of resolving base classes
+    BASEOKdone,         // all base classes are resolved
+    BASEOKsemanticdone, // all base classes semantic done
+};
+
+enum StructPOD
+{
+    ISPODno,            // struct is not POD
+    ISPODyes,           // struct is POD
+    ISPODfwd,           // POD not yet computed
+};
+
+enum Abstract
+{
+    ABSfwdref = 0,      // whether an abstract class is not yet computed
+    ABSyes,             // is abstract class
+    ABSno,              // is not abstract class
+};
+
+FuncDeclaration *hasIdentityOpAssign(AggregateDeclaration *ad, Scope *sc);
+FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc);
+bool needOpEquals(StructDeclaration *sd);
+FuncDeclaration *buildOpEquals(StructDeclaration *sd, Scope *sc);
+FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc);
+FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc);
+FuncDeclaration *buildXtoHash(StructDeclaration *ad, Scope *sc);
+FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc);
+FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc);
+FuncDeclaration *buildInv(AggregateDeclaration *ad, Scope *sc);
+
+class AggregateDeclaration : public ScopeDsymbol
+{
+public:
+    Type *type;
+    StorageClass storage_class;
+    Prot protection;
+    unsigned structsize;        // size of struct
+    unsigned alignsize;         // size of struct for alignment purposes
+    VarDeclarations fields;     // VarDeclaration fields
+    Sizeok sizeok;              // set when structsize contains valid data
+    Dsymbol *deferred;          // any deferred semantic2() or semantic3() symbol
+    bool isdeprecated;          // true if deprecated
+
+    /* !=NULL if is nested
+     * pointing to the dsymbol that directly enclosing it.
+     * 1. The function that enclosing it (nested struct and class)
+     * 2. The class that enclosing it (nested class only)
+     * 3. If enclosing aggregate is template, its enclosing dsymbol.
+     * See AggregateDeclaraton::makeNested for the details.
+     */
+    Dsymbol *enclosing;
+    VarDeclaration *vthis;      // 'this' parameter if this aggregate is nested
+    // Special member functions
+    FuncDeclarations invs;              // Array of invariants
+    FuncDeclaration *inv;               // invariant
+    NewDeclaration *aggNew;             // allocator
+    DeleteDeclaration *aggDelete;       // deallocator
+
+    Dsymbol *ctor;                      // CtorDeclaration or TemplateDeclaration
+
+    // default constructor - should have no arguments, because
+    // it would be stored in TypeInfo_Class.defaultConstructor
+    CtorDeclaration *defaultCtor;
+
+    Dsymbol *aliasthis;         // forward unresolved lookups to aliasthis
+    bool noDefaultCtor;         // no default construction
+
+    FuncDeclarations dtors;     // Array of destructors
+    FuncDeclaration *dtor;      // aggregate destructor
+
+    Expression *getRTInfo;      // pointer to GC info generated by object.RTInfo(this)
+
+    AggregateDeclaration(Loc loc, Identifier *id);
+    virtual Scope *newScope(Scope *sc);
+    void setScope(Scope *sc);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    bool determineFields();
+    bool determineSize(Loc loc);
+    virtual void finalizeSize() = 0;
+    d_uns64 size(Loc loc);
+    bool checkOverlappedFields();
+    bool fill(Loc loc, Expressions *elements, bool ctorinit);
+    static void alignmember(structalign_t salign, unsigned size, unsigned *poffset);
+    static unsigned placeField(unsigned *nextoffset,
+        unsigned memsize, unsigned memalignsize, structalign_t memalign,
+        unsigned *paggsize, unsigned *paggalignsize, bool isunion);
+    Type *getType();
+    bool isDeprecated();         // is aggregate deprecated?
+    bool isNested();
+    void makeNested();
+    bool isExport();
+    Dsymbol *searchCtor();
+
+    Prot prot();
+
+    // 'this' type
+    Type *handleType() { return type; }
+
+    // Back end
+    Symbol *stag;               // tag symbol for debug data
+    Symbol *sinit;
+
+    AggregateDeclaration *isAggregateDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+struct StructFlags
+{
+    typedef unsigned Type;
+    enum Enum
+    {
+        hasPointers = 0x1, // NB: should use noPointers as in ClassFlags
+    };
+};
+
+class StructDeclaration : public AggregateDeclaration
+{
+public:
+    int zeroInit;               // !=0 if initialize with 0 fill
+    bool hasIdentityAssign;     // true if has identity opAssign
+    bool hasIdentityEquals;     // true if has identity opEquals
+    FuncDeclarations postblits; // Array of postblit functions
+    FuncDeclaration *postblit;  // aggregate postblit
+
+    FuncDeclaration *xeq;       // TypeInfo_Struct.xopEquals
+    FuncDeclaration *xcmp;      // TypeInfo_Struct.xopCmp
+    FuncDeclaration *xhash;     // TypeInfo_Struct.xtoHash
+    static FuncDeclaration *xerreq;      // object.xopEquals
+    static FuncDeclaration *xerrcmp;     // object.xopCmp
+
+    structalign_t alignment;    // alignment applied outside of the struct
+    StructPOD ispod;            // if struct is POD
+
+    // For 64 bit Efl function call/return ABI
+    Type *arg1type;
+    Type *arg2type;
+
+    // Even if struct is defined as non-root symbol, some built-in operations
+    // (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
+    // For those, today TypeInfo_Struct is generated in COMDAT.
+    bool requestTypeInfo;
+
+    StructDeclaration(Loc loc, Identifier *id, bool inObject);
+    static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void semanticTypeInfoMembers();
+    Dsymbol *search(Loc, Identifier *ident, int flags = SearchLocalsOnly);
+    const char *kind();
+    void finalizeSize();
+    bool fit(Loc loc, Scope *sc, Expressions *elements, Type *stype);
+    bool isPOD();
+
+    StructDeclaration *isStructDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class UnionDeclaration : public StructDeclaration
+{
+public:
+    UnionDeclaration(Loc loc, Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    const char *kind();
+
+    UnionDeclaration *isUnionDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+struct BaseClass
+{
+    Type *type;                         // (before semantic processing)
+
+    ClassDeclaration *sym;
+    unsigned offset;                    // 'this' pointer offset
+    // for interfaces: Array of FuncDeclaration's
+    // making up the vtbl[]
+    FuncDeclarations vtbl;
+
+    DArray<BaseClass> baseInterfaces;   // if BaseClass is an interface, these
+                                        // are a copy of the InterfaceDeclaration::interfaces
+
+    BaseClass();
+    BaseClass(Type *type);
+
+    bool fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance);
+    void copyBaseInterfaces(BaseClasses *);
+};
+
+struct ClassFlags
+{
+    typedef unsigned Type;
+    enum Enum
+    {
+        isCOMclass = 0x1,
+        noPointers = 0x2,
+        hasOffTi = 0x4,
+        hasCtor = 0x8,
+        hasGetMembers = 0x10,
+        hasTypeInfo = 0x20,
+        isAbstract = 0x40,
+        isCPPclass = 0x80,
+        hasDtor = 0x100,
+    };
+};
+
+class ClassDeclaration : public AggregateDeclaration
+{
+public:
+    static ClassDeclaration *object;
+    static ClassDeclaration *throwable;
+    static ClassDeclaration *exception;
+    static ClassDeclaration *errorException;
+    static ClassDeclaration *cpp_type_info_ptr;
+
+    ClassDeclaration *baseClass;        // NULL only if this is Object
+    FuncDeclaration *staticCtor;
+    FuncDeclaration *staticDtor;
+    Dsymbols vtbl;                      // Array of FuncDeclaration's making up the vtbl[]
+    Dsymbols vtblFinal;                 // More FuncDeclaration's that aren't in vtbl[]
+
+    BaseClasses *baseclasses;           // Array of BaseClass's; first is super,
+                                        // rest are Interface's
+
+    DArray<BaseClass*> interfaces;      // interfaces[interfaces_dim] for this class
+                                        // (does not include baseClass)
+
+    BaseClasses *vtblInterfaces;        // array of base interfaces that have
+                                        // their own vtbl[]
+
+    TypeInfoClassDeclaration *vclassinfo;       // the ClassInfo object for this ClassDeclaration
+    bool com;                           // true if this is a COM class (meaning it derives from IUnknown)
+    bool cpp;                           // true if this is a C++ interface
+    bool isobjc;                        // true if this is an Objective-C class/interface
+    bool isscope;                       // true if this is a scope class
+    Abstract isabstract;                // 0: fwdref, 1: is abstract class, 2: not abstract
+    int inuse;                          // to prevent recursive attempts
+    Baseok baseok;                      // set the progress of base classes resolving
+    Symbol *cpp_type_info_ptr_sym;      // cached instance of class Id.cpp_type_info_ptr
+
+    ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject = false);
+    static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Scope *newScope(Scope *sc);
+    void semantic(Scope *sc);
+    bool isBaseOf2(ClassDeclaration *cd);
+
+    #define OFFSET_RUNTIME 0x76543210
+    #define OFFSET_FWDREF 0x76543211
+    virtual bool isBaseOf(ClassDeclaration *cd, int *poffset);
+
+    bool isBaseInfoComplete();
+    Dsymbol *search(Loc, Identifier *ident, int flags = SearchLocalsOnly);
+    ClassDeclaration *searchBase(Identifier *ident);
+    void finalizeSize();
+    bool isFuncHidden(FuncDeclaration *fd);
+    FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
+    void interfaceSemantic(Scope *sc);
+    bool isCOMclass() const;
+    virtual bool isCOMinterface() const;
+    bool isCPPclass() const;
+    virtual bool isCPPinterface() const;
+    bool isAbstract();
+    virtual int vtblOffset() const;
+    const char *kind();
+
+    void addLocalClass(ClassDeclarations *);
+
+    // Back end
+    Symbol *vtblsym;
+
+    ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class InterfaceDeclaration : public ClassDeclaration
+{
+public:
+    InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Scope *newScope(Scope *sc);
+    void semantic(Scope *sc);
+    bool isBaseOf(ClassDeclaration *cd, int *poffset);
+    bool isBaseOf(BaseClass *bc, int *poffset);
+    const char *kind();
+    int vtblOffset() const;
+    bool isCPPinterface() const;
+    bool isCOMinterface() const;
+
+    InterfaceDeclaration *isInterfaceDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#endif /* DMD_AGGREGATE_H */
diff --git a/gcc/d/dfrontend/aliasthis.c b/gcc/d/dfrontend/aliasthis.c
new file mode 100644
index 00000000000..4ce53fc2e54
--- /dev/null
+++ b/gcc/d/dfrontend/aliasthis.c
@@ -0,0 +1,158 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 2009-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/aliasthis.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "identifier.h"
+#include "aliasthis.h"
+#include "scope.h"
+#include "aggregate.h"
+#include "dsymbol.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "tokens.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+
+Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag)
+{
+    AggregateDeclaration *ad = isAggregate(e->type);
+
+    if (ad && ad->aliasthis)
+    {
+        unsigned olderrors = gag ? global.startGagging() : 0;
+
+        Loc loc = e->loc;
+        Type *tthis = (e->op == TOKtype ? e->type : NULL);
+        e = new DotIdExp(loc, e, ad->aliasthis->ident);
+        e = semantic(e, sc);
+        if (tthis && ad->aliasthis->needThis())
+        {
+            if (e->op == TOKvar)
+            {
+                if (FuncDeclaration *fd = ((VarExp *)e)->var->isFuncDeclaration())
+                {
+                    // Bugzilla 13009: Support better match for the overloaded alias this.
+                    bool hasOverloads = false;
+                    if (FuncDeclaration *f = fd->overloadModMatch(loc, tthis, hasOverloads))
+                    {
+                        if (!hasOverloads)
+                            fd = f;     // use exact match
+                        e = new VarExp(loc, fd, hasOverloads);
+                        e->type = f->type;
+                        e = new CallExp(loc, e);
+                        goto L1;
+                    }
+                }
+            }
+            /* non-@property function is not called inside typeof(),
+             * so resolve it ahead.
+             */
+            {
+            int save = sc->intypeof;
+            sc->intypeof = 1;   // bypass "need this" error check
+            e = resolveProperties(sc, e);
+            sc->intypeof = save;
+            }
+
+        L1:
+            e = new TypeExp(loc, new TypeTypeof(loc, e));
+            e = semantic(e, sc);
+        }
+        e = resolveProperties(sc, e);
+
+        if (gag && global.endGagging(olderrors))
+            e = NULL;
+    }
+
+    return e;
+}
+
+AliasThis::AliasThis(Loc loc, Identifier *ident)
+    : Dsymbol(NULL)             // it's anonymous (no identifier)
+{
+    this->loc = loc;
+    this->ident = ident;
+}
+
+Dsymbol *AliasThis::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    /* Since there is no semantic information stored here,
+     * we don't need to copy it.
+     */
+    return this;
+}
+
+void AliasThis::semantic(Scope *sc)
+{
+    Dsymbol *p = sc->parent->pastMixin();
+    AggregateDeclaration *ad = p->isAggregateDeclaration();
+    if (!ad)
+    {
+        ::error(loc, "alias this can only be a member of aggregate, not %s %s",
+            p->kind(), p->toChars());
+        return;
+    }
+
+    assert(ad->members);
+    Dsymbol *s = ad->search(loc, ident);
+    if (!s)
+    {
+        s = sc->search(loc, ident, NULL);
+        if (s)
+            ::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars());
+        else
+            ::error(loc, "undefined identifier %s", ident->toChars());
+        return;
+    }
+    else if (ad->aliasthis && s != ad->aliasthis)
+    {
+        ::error(loc, "there can be only one alias this");
+        return;
+    }
+
+    if (ad->type->ty == Tstruct && ((TypeStruct *)ad->type)->sym != ad)
+    {
+        AggregateDeclaration *ad2 = ((TypeStruct *)ad->type)->sym;
+        assert(ad2->type == Type::terror);
+        ad->aliasthis = ad2->aliasthis;
+        return;
+    }
+
+    /* disable the alias this conversion so the implicit conversion check
+     * doesn't use it.
+     */
+    ad->aliasthis = NULL;
+
+    Dsymbol *sx = s;
+    if (sx->isAliasDeclaration())
+        sx = sx->toAlias();
+    Declaration *d = sx->isDeclaration();
+    if (d && !d->isTupleDeclaration())
+    {
+        Type *t = d->type;
+        assert(t);
+        if (ad->type->implicitConvTo(t) > MATCHnomatch)
+        {
+            ::error(loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars());
+        }
+    }
+
+    ad->aliasthis = s;
+}
+
+const char *AliasThis::kind()
+{
+    return "alias this";
+}
diff --git a/gcc/d/dfrontend/aliasthis.h b/gcc/d/dfrontend/aliasthis.h
new file mode 100644
index 00000000000..dfc136aee44
--- /dev/null
+++ b/gcc/d/dfrontend/aliasthis.h
@@ -0,0 +1,39 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 2009-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/aliasthis.h
+ */
+
+#ifndef DMD_ALIASTHIS_H
+#define DMD_ALIASTHIS_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "mars.h"
+#include "dsymbol.h"
+
+/**************************************************************/
+
+class AliasThis : public Dsymbol
+{
+public:
+   // alias Identifier this;
+    Identifier *ident;
+
+    AliasThis(Loc loc, Identifier *ident);
+
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    const char *kind();
+    AliasThis *isAliasThis() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#endif
diff --git a/gcc/d/dfrontend/apply.c b/gcc/d/dfrontend/apply.c
new file mode 100644
index 00000000000..bf14cd06769
--- /dev/null
+++ b/gcc/d/dfrontend/apply.c
@@ -0,0 +1,145 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/apply.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "expression.h"
+#include "visitor.h"
+
+
+/**************************************
+ * An Expression tree walker that will visit each Expression e in the tree,
+ * in depth-first evaluation order, and call fp(e,param) on it.
+ * fp() signals whether the walking continues with its return value:
+ * Returns:
+ *      0       continue
+ *      1       done
+ * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
+ * Creating an iterator for this would be much more complex.
+ */
+
+class PostorderExpressionVisitor : public StoppableVisitor
+{
+public:
+    StoppableVisitor *v;
+    PostorderExpressionVisitor(StoppableVisitor *v) : v(v) {}
+
+    bool doCond(Expression *e)
+    {
+        if (!stop && e)
+            e->accept(this);
+        return stop;
+    }
+    bool doCond(Expressions *e)
+    {
+        if (!e)
+            return false;
+        for (size_t i = 0; i < e->dim && !stop; i++)
+            doCond((*e)[i]);
+        return stop;
+    }
+    bool applyTo(Expression *e)
+    {
+        e->accept(v);
+        stop = v->stop;
+        return true;
+    }
+
+    void visit(Expression *e)
+    {
+        applyTo(e);
+    }
+
+    void visit(NewExp *e)
+    {
+        //printf("NewExp::apply(): %s\n", toChars());
+
+        doCond(e->thisexp) || doCond(e->newargs) || doCond(e->arguments) || applyTo(e);
+    }
+
+    void visit(NewAnonClassExp *e)
+    {
+        //printf("NewAnonClassExp::apply(): %s\n", toChars());
+
+        doCond(e->thisexp) || doCond(e->newargs) || doCond(e->arguments) || applyTo(e);
+    }
+
+    void visit(UnaExp *e)
+    {
+        doCond(e->e1) || applyTo(e);
+    }
+
+    void visit(BinExp *e)
+    {
+        doCond(e->e1) || doCond(e->e2) || applyTo(e);
+    }
+
+    void visit(AssertExp *e)
+    {
+        //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
+        doCond(e->e1) || doCond(e->msg) || applyTo(e);
+    }
+
+    void visit(CallExp *e)
+    {
+        //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
+        doCond(e->e1) || doCond(e->arguments) || applyTo(e);
+    }
+
+    void visit(ArrayExp *e)
+    {
+        //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
+        doCond(e->e1) || doCond(e->arguments) || applyTo(e);
+    }
+
+    void visit(SliceExp *e)
+    {
+        doCond(e->e1) || doCond(e->lwr) || doCond(e->upr) || applyTo(e);
+    }
+
+    void visit(ArrayLiteralExp *e)
+    {
+        doCond(e->basis) || doCond(e->elements) || applyTo(e);
+    }
+
+    void visit(AssocArrayLiteralExp *e)
+    {
+        doCond(e->keys) || doCond(e->values) || applyTo(e);
+    }
+
+    void visit(StructLiteralExp *e)
+    {
+        if (e->stageflags & stageApply) return;
+        int old = e->stageflags;
+        e->stageflags |= stageApply;
+        doCond(e->elements) || applyTo(e);
+        e->stageflags = old;
+    }
+
+    void visit(TupleExp *e)
+    {
+        doCond(e->e0) || doCond(e->exps) || applyTo(e);
+    }
+
+    void visit(CondExp *e)
+    {
+        doCond(e->econd) || doCond(e->e1) || doCond(e->e2) || applyTo(e);
+    }
+};
+
+bool walkPostorder(Expression *e, StoppableVisitor *v)
+{
+    PostorderExpressionVisitor pv(v);
+    e->accept(&pv);
+    return v->stop;
+}
diff --git a/gcc/d/dfrontend/argtypes.c b/gcc/d/dfrontend/argtypes.c
new file mode 100644
index 00000000000..2d170fe39f7
--- /dev/null
+++ b/gcc/d/dfrontend/argtypes.c
@@ -0,0 +1,502 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 2010-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/argtypes.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "checkedint.h"
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "mtype.h"
+#include "scope.h"
+#include "init.h"
+#include "expression.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "template.h"
+#include "id.h"
+#include "enum.h"
+#include "import.h"
+#include "aggregate.h"
+#include "hdrgen.h"
+
+/****************************************************
+ * This breaks a type down into 'simpler' types that can be passed to a function
+ * in registers, and returned in registers.
+ * It's highly platform dependent.
+ * Params:
+ *      t = type to break down
+ * Returns:
+ *      tuple of types, each element can be passed in a register.
+ *      A tuple of zero length means the type cannot be passed/returned in registers.
+ */
+
+TypeTuple *toArgTypes(Type *t)
+{
+    class ToArgTypes : public Visitor
+    {
+    public:
+        TypeTuple *result;
+
+        ToArgTypes()
+        {
+            result = NULL;
+        }
+
+        void visit(Type *)
+        {
+            // not valid for a parameter
+        }
+
+        void visit(TypeError *)
+        {
+            result = new TypeTuple(Type::terror);
+        }
+
+        void visit(TypeBasic *t)
+        {
+            Type *t1 = NULL;
+            Type *t2 = NULL;
+            switch (t->ty)
+            {
+                case Tvoid:
+                     return;
+
+                case Tbool:
+                case Tint8:
+                case Tuns8:
+                case Tint16:
+                case Tuns16:
+                case Tint32:
+                case Tuns32:
+                case Tfloat32:
+                case Tint64:
+                case Tuns64:
+                case Tint128:
+                case Tuns128:
+                case Tfloat64:
+                case Tfloat80:
+                    t1 = t;
+                    break;
+
+                case Timaginary32:
+                    t1 = Type::tfloat32;
+                    break;
+
+                case Timaginary64:
+                    t1 = Type::tfloat64;
+                    break;
+
+                case Timaginary80:
+                    t1 = Type::tfloat80;
+                    break;
+
+                case Tcomplex32:
+                    if (global.params.is64bit)
+                        t1 = Type::tfloat64;
+                    else
+                    {
+                        t1 = Type::tfloat64;
+                        t2 = Type::tfloat64;
+                    }
+                    break;
+
+                case Tcomplex64:
+                    t1 = Type::tfloat64;
+                    t2 = Type::tfloat64;
+                    break;
+
+                case Tcomplex80:
+                    t1 = Type::tfloat80;
+                    t2 = Type::tfloat80;
+                    break;
+
+                case Tchar:
+                    t1 = Type::tuns8;
+                    break;
+
+                case Twchar:
+                    t1 = Type::tuns16;
+                    break;
+
+                case Tdchar:
+                    t1 = Type::tuns32;
+                    break;
+
+                default:
+                    assert(0);
+            }
+
+            if (t1)
+            {
+                if (t2)
+                    result = new TypeTuple(t1, t2);
+                else
+                    result = new TypeTuple(t1);
+            }
+            else
+                result = new TypeTuple();
+        }
+
+        void visit(TypeVector *t)
+        {
+            result = new TypeTuple(t);
+        }
+
+        void visit(TypeSArray *t)
+        {
+            if (t->dim)
+            {
+                /* Should really be done as if it were a struct with dim members
+                 * of the array's elements.
+                 * I.e. int[2] should be done like struct S { int a; int b; }
+                 */
+                dinteger_t sz = t->dim->toInteger();
+                // T[1] should be passed like T
+                if (sz == 1)
+                {
+                    t->next->accept(this);
+                    return;
+                }
+            }
+            result = new TypeTuple();     // pass on the stack for efficiency
+        }
+
+        void visit(TypeAArray *)
+        {
+            result = new TypeTuple(Type::tvoidptr);
+        }
+
+        void visit(TypePointer *)
+        {
+            result = new TypeTuple(Type::tvoidptr);
+        }
+
+        /*************************************
+         * Convert a floating point type into the equivalent integral type.
+         */
+
+        static Type *mergeFloatToInt(Type *t)
+        {
+            switch (t->ty)
+            {
+                case Tfloat32:
+                case Timaginary32:
+                    t = Type::tint32;
+                    break;
+                case Tfloat64:
+                case Timaginary64:
+                case Tcomplex32:
+                    t = Type::tint64;
+                    break;
+                default:
+        #ifdef DEBUG
+                    printf("mergeFloatToInt() %s\n", t->toChars());
+        #endif
+                    assert(0);
+            }
+            return t;
+        }
+
+        /*************************************
+         * This merges two types into an 8byte type.
+         * Params:
+         *      t1 = first type (can be null)
+         *      t2 = second type (can be null)
+         *      offset2 = offset of t2 from start of t1
+         * Returns:
+         *      type that encompasses both t1 and t2, null if cannot be done
+         */
+
+        static Type *argtypemerge(Type *t1, Type *t2, unsigned offset2)
+        {
+            //printf("argtypemerge(%s, %s, %d)\n", t1 ? t1->toChars() : "", t2 ? t2->toChars() : "", offset2);
+            if (!t1)
+            {   assert(!t2 || offset2 == 0);
+                return t2;
+            }
+            if (!t2)
+                return t1;
+
+            const d_uns64 sz1 = t1->size(Loc());
+            const d_uns64 sz2 = t2->size(Loc());
+            assert(sz1 != SIZE_INVALID && sz2 != SIZE_INVALID);
+
+            if (t1->ty != t2->ty &&
+                (t1->ty == Tfloat80 || t2->ty == Tfloat80))
+                return NULL;
+
+            // [float,float] => [cfloat]
+            if (t1->ty == Tfloat32 && t2->ty == Tfloat32 && offset2 == 4)
+                return Type::tfloat64;
+
+            // Merging floating and non-floating types produces the non-floating type
+            if (t1->isfloating())
+            {
+                if (!t2->isfloating())
+                    t1 = mergeFloatToInt(t1);
+            }
+            else if (t2->isfloating())
+                t2 = mergeFloatToInt(t2);
+
+            Type *t;
+
+            // Pick type with larger size
+            if (sz1 < sz2)
+                t = t2;
+            else
+                t = t1;
+
+            // If t2 does not lie within t1, need to increase the size of t to enclose both
+            assert(sz2 < UINT64_MAX - UINT32_MAX);
+            if (offset2 && sz1 < offset2 + sz2)
+            {
+                switch (offset2 + sz2)
+                {
+                    case 2:
+                        t = Type::tint16;
+                        break;
+                    case 3:
+                    case 4:
+                        t = Type::tint32;
+                        break;
+                    default:
+                        t = Type::tint64;
+                        break;
+                }
+            }
+            return t;
+        }
+
+        void visit(TypeDArray *)
+        {
+            /* Should be done as if it were:
+             * struct S { size_t length; void* ptr; }
+             */
+            if (global.params.is64bit && !global.params.isLP64)
+            {
+                // For AMD64 ILP32 ABI, D arrays fit into a single integer register.
+                unsigned offset = (unsigned)Type::tsize_t->size(Loc());
+                Type *t = argtypemerge(Type::tsize_t, Type::tvoidptr, offset);
+                if (t)
+                {
+                    result = new TypeTuple(t);
+                    return;
+                }
+            }
+            result = new TypeTuple(Type::tsize_t, Type::tvoidptr);
+        }
+
+        void visit(TypeDelegate *)
+        {
+            /* Should be done as if it were:
+             * struct S { size_t length; void* ptr; }
+             */
+            if (global.params.is64bit && !global.params.isLP64)
+            {
+                // For AMD64 ILP32 ABI, delegates fit into a single integer register.
+                unsigned offset = (unsigned)Type::tsize_t->size(Loc());
+                Type *t = argtypemerge(Type::tsize_t, Type::tvoidptr, offset);
+                if (t)
+                {
+                    result = new TypeTuple(t);
+                    return;
+                }
+            }
+            result = new TypeTuple(Type::tvoidptr, Type::tvoidptr);
+        }
+
+        void visit(TypeStruct *t)
+        {
+            //printf("TypeStruct::toArgTypes() %s\n", t->toChars());
+            if (!t->sym->isPOD() || t->sym->fields.dim == 0)
+            {
+            Lmemory:
+                //printf("\ttoArgTypes() %s => [ ]\n", t->toChars());
+                result = new TypeTuple();         // pass on the stack
+                return;
+            }
+            Type *t1 = NULL;
+            Type *t2 = NULL;
+            const d_uns64 sz = t->size(Loc());
+            assert(sz < 0xFFFFFFFF);
+            switch ((unsigned)sz)
+            {
+                case 1:
+                    t1 = Type::tint8;
+                    break;
+                case 2:
+                    t1 = Type::tint16;
+                    break;
+                case 3:
+                    if (!global.params.is64bit)
+                        goto Lmemory;
+                case 4:
+                    t1 = Type::tint32;
+                    break;
+                case 5:
+                case 6:
+                case 7:
+                    if (!global.params.is64bit)
+                        goto Lmemory;
+                case 8:
+                    t1 = Type::tint64;
+                    break;
+                case 16:
+                    t1 = NULL;                   // could be a TypeVector
+                    break;
+                case 9:
+                case 10:
+                case 11:
+                case 12:
+                case 13:
+                case 14:
+                case 15:
+                    if (!global.params.is64bit)
+                        goto Lmemory;
+                    t1 = NULL;
+                    break;
+                default:
+                    goto Lmemory;
+            }
+            if (global.params.is64bit && t->sym->fields.dim)
+            {
+        #if 1
+                t1 = NULL;
+                for (size_t i = 0; i < t->sym->fields.dim; i++)
+                {
+                    VarDeclaration *f = t->sym->fields[i];
+                    //printf("  [%d] %s f->type = %s\n", (int)i, f->toChars(), f->type->toChars());
+
+                    TypeTuple *tup = toArgTypes(f->type);
+                    if (!tup)
+                        goto Lmemory;
+                    size_t dim = tup->arguments->dim;
+                    Type *ft1 = NULL;
+                    Type *ft2 = NULL;
+                    switch (dim)
+                    {
+                        case 2:
+                            ft1 = (*tup->arguments)[0]->type;
+                            ft2 = (*tup->arguments)[1]->type;
+                            break;
+                        case 1:
+                            if (f->offset < 8)
+                                ft1 = (*tup->arguments)[0]->type;
+                            else
+                                ft2 = (*tup->arguments)[0]->type;
+                            break;
+                        default:
+                            goto Lmemory;
+                    }
+
+                    if (f->offset & 7)
+                    {
+                        // Misaligned fields goto Lmemory
+                        unsigned alignsz = f->type->alignsize();
+                        if (f->offset & (alignsz - 1))
+                            goto Lmemory;
+
+                        // Fields that overlap the 8byte boundary goto Lmemory
+                        const d_uns64 fieldsz = f->type->size(Loc());
+                        assert(fieldsz != SIZE_INVALID && fieldsz < UINT64_MAX - UINT32_MAX);
+                        if (f->offset < 8 && (f->offset + fieldsz) > 8)
+                            goto Lmemory;
+                    }
+
+                    // First field in 8byte must be at start of 8byte
+                    assert(t1 || f->offset == 0);
+                    //printf("ft1 = %s\n", ft1 ? ft1->toChars() : "null");
+                    //printf("ft2 = %s\n", ft2 ? ft2->toChars() : "null");
+                    if (ft1)
+                    {
+                        t1 = argtypemerge(t1, ft1, f->offset);
+                        if (!t1)
+                            goto Lmemory;
+                    }
+
+                    if (ft2)
+                    {
+                        unsigned off2 = f->offset;
+                        if (ft1)
+                            off2 = 8;
+                        if (!t2 && off2 != 8)
+                            goto Lmemory;
+                        assert(t2 || off2 == 8);
+                        t2 = argtypemerge(t2, ft2, off2 - 8);
+                        if (!t2)
+                            goto Lmemory;
+                    }
+                }
+
+                if (t2)
+                {
+                    if (t1->isfloating() && t2->isfloating())
+                    {
+                        if ((t1->ty == Tfloat32 || t1->ty == Tfloat64) &&
+                            (t2->ty == Tfloat32 || t2->ty == Tfloat64))
+                            ;
+                        else
+                            goto Lmemory;
+                    }
+                    else if (t1->isfloating())
+                        goto Lmemory;
+                    else if (t2->isfloating())
+                        goto Lmemory;
+                    else
+                        ;
+                }
+        #else
+                if (t->sym->fields.dim == 1)
+                {
+                    VarDeclaration *f = t->sym->fields[0];
+                    //printf("f->type = %s\n", f->type->toChars());
+                    TypeTuple *tup = toArgTypes(f->type);
+                    if (tup)
+                    {
+                        size_t dim = tup->arguments->dim;
+                        if (dim == 1)
+                            t1 = (*tup->arguments)[0]->type;
+                    }
+                }
+        #endif
+            }
+
+            //printf("\ttoArgTypes() %s => [%s,%s]\n", t->toChars(), t1 ? t1->toChars() : "", t2 ? t2->toChars() : "");
+
+            if (t1)
+            {
+                //if (t1) printf("test1: %s => %s\n", toChars(), t1->toChars());
+                if (t2)
+                    result = new TypeTuple(t1, t2);
+                else
+                    result = new TypeTuple(t1);
+            }
+            else
+                goto Lmemory;
+        }
+
+        void visit(TypeEnum *t)
+        {
+            t->toBasetype()->accept(this);
+        }
+
+        void visit(TypeClass *)
+        {
+            result = new TypeTuple(Type::tvoidptr);
+        }
+    };
+
+    ToArgTypes v;
+    t->accept(&v);
+    return v.result;
+}
diff --git a/gcc/d/dfrontend/array.h b/gcc/d/dfrontend/array.h
new file mode 100644
index 00000000000..663a51877b9
--- /dev/null
+++ b/gcc/d/dfrontend/array.h
@@ -0,0 +1,237 @@
+/* Copyright (c) 2011-2014 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/dlang/dmd/blob/master/src/root/array.h
+ */
+
+#ifndef ARRAY_H
+#define ARRAY_H
+
+#if __DMC__
+#pragma once
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "object.h"
+#include "rmem.h"
+
+template <typename TYPE>
+struct Array
+{
+    d_size_t dim;
+    TYPE *data;
+
+  private:
+    Array(const Array&);
+
+    d_size_t allocdim;
+    #define SMALLARRAYCAP       1
+    TYPE smallarray[SMALLARRAYCAP];    // inline storage for small arrays
+
+  public:
+    Array()
+    {
+        data = SMALLARRAYCAP ? &smallarray[0] : NULL;
+        dim = 0;
+        allocdim = SMALLARRAYCAP;
+    }
+
+    ~Array()
+    {
+        if (data != &smallarray[0])
+            mem.xfree(data);
+    }
+
+    char *toChars()
+    {
+        const char **buf = (const char **)mem.xmalloc(dim * sizeof(const char *));
+        d_size_t len = 2;
+        for (d_size_t u = 0; u < dim; u++)
+        {
+            buf[u] = ((RootObject *)data[u])->toChars();
+            len += strlen(buf[u]) + 1;
+        }
+        char *str = (char *)mem.xmalloc(len);
+
+        str[0] = '[';
+        char *p = str + 1;
+        for (d_size_t u = 0; u < dim; u++)
+        {
+            if (u)
+                *p++ = ',';
+            len = strlen(buf[u]);
+            memcpy(p,buf[u],len);
+            p += len;
+        }
+        *p++ = ']';
+        *p = 0;
+        mem.xfree(buf);
+        return str;
+    }
+
+    void reserve(d_size_t nentries)
+    {
+        //printf("Array::reserve: dim = %d, allocdim = %d, nentries = %d\n", (int)dim, (int)allocdim, (int)nentries);
+        if (allocdim - dim < nentries)
+        {
+            if (allocdim == 0)
+            {   // Not properly initialized, someone memset it to zero
+                if (nentries <= SMALLARRAYCAP)
+                {   allocdim = SMALLARRAYCAP;
+                    data = SMALLARRAYCAP ? &smallarray[0] : NULL;
+                }
+                else
+                {   allocdim = nentries;
+                    data = (TYPE *)mem.xmalloc(allocdim * sizeof(*data));
+                }
+            }
+            else if (allocdim == SMALLARRAYCAP)
+            {
+                allocdim = dim + nentries;
+                data = (TYPE *)mem.xmalloc(allocdim * sizeof(*data));
+                memcpy(data, &smallarray[0], dim * sizeof(*data));
+            }
+            else
+            {   allocdim = dim + nentries;
+                data = (TYPE *)mem.xrealloc(data, allocdim * sizeof(*data));
+            }
+        }
+    }
+
+    void setDim(d_size_t newdim)
+    {
+        if (dim < newdim)
+        {
+            reserve(newdim - dim);
+        }
+        dim = newdim;
+    }
+
+    TYPE pop()
+    {
+        return data[--dim];
+    }
+
+    void shift(TYPE ptr)
+    {
+        reserve(1);
+        memmove(data + 1, data, dim * sizeof(*data));
+        data[0] = ptr;
+        dim++;
+    }
+
+    void remove(d_size_t i)
+    {
+        if (dim - i - 1)
+            memmove(data + i, data + i + 1, (dim - i - 1) * sizeof(data[0]));
+        dim--;
+    }
+
+    void zero()
+    {
+        memset(data,0,dim * sizeof(data[0]));
+    }
+
+    void sort()
+    {
+        struct ArraySort
+        {
+            static int
+    #if _WIN32
+              __cdecl
+    #endif
+            Array_sort_compare(const void *x, const void *y)
+            {
+                RootObject *ox = *(RootObject **)const_cast<void *>(x);
+                RootObject *oy = *(RootObject **)const_cast<void *>(y);
+
+                return ox->compare(oy);
+            }
+        };
+
+        if (dim)
+        {
+            qsort(data, dim, sizeof(RootObject *), &ArraySort::Array_sort_compare);
+        }
+    }
+
+    TYPE *tdata()
+    {
+        return data;
+    }
+
+    TYPE& operator[] (d_size_t index)
+    {
+#ifdef DEBUG
+        assert(index < dim);
+#endif
+        return data[index];
+    }
+
+    void insert(d_size_t index, TYPE v)
+    {
+        reserve(1);
+        memmove(data + index + 1, data + index, (dim - index) * sizeof(*data));
+        data[index] = v;
+        dim++;
+    }
+
+    void insert(d_size_t index, Array *a)
+    {
+        if (a)
+        {
+            d_size_t d = a->dim;
+            reserve(d);
+            if (dim != index)
+                memmove(data + index + d, data + index, (dim - index) * sizeof(*data));
+            memcpy(data + index, a->data, d * sizeof(*data));
+            dim += d;
+        }
+    }
+
+    void append(Array *a)
+    {
+        insert(dim, a);
+    }
+
+    void push(TYPE a)
+    {
+        reserve(1);
+        data[dim++] = a;
+    }
+
+    Array *copy()
+    {
+        Array *a = new Array();
+        a->setDim(dim);
+        memcpy(a->data, data, dim * sizeof(*data));
+        return a;
+    }
+};
+
+struct BitArray
+{
+    BitArray()
+      : len(0)
+      , ptr(NULL)
+    {}
+
+    ~BitArray()
+    {
+        mem.xfree(ptr);
+    }
+
+    d_size_t len;
+    d_size_t *ptr;
+
+private:
+    BitArray(const BitArray&);
+};
+
+#endif
diff --git a/gcc/d/dfrontend/arrayop.c b/gcc/d/dfrontend/arrayop.c
new file mode 100644
index 00000000000..2ff3b7a9215
--- /dev/null
+++ b/gcc/d/dfrontend/arrayop.c
@@ -0,0 +1,639 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/arrayop.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "rmem.h"
+
+#include "aav.h"
+
+#include "expression.h"
+#include "statement.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "scope.h"
+#include "id.h"
+#include "module.h"
+#include "init.h"
+#include "tokens.h"
+
+void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments);
+Expression *buildArrayLoop(Expression *e, Parameters *fparams);
+Expression *semantic(Expression *e, Scope *sc);
+
+/**************************************
+ * Hash table of array op functions already generated or known about.
+ */
+
+AA *arrayfuncs;
+
+/**************************************
+ * Structure to contain information needed to insert an array op call
+ */
+
+FuncDeclaration *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc, Loc loc)
+{
+    Parameters *fparams = new Parameters();
+    Expression *loopbody = buildArrayLoop(exp, fparams);
+
+    /* Construct the function body:
+     *  foreach (i; 0 .. p.length)    for (size_t i = 0; i < p.length; i++)
+     *      loopbody;
+     *  return p;
+     */
+
+    Parameter *p = (*fparams)[0];
+    // foreach (i; 0 .. p.length)
+    Statement *s1 = new ForeachRangeStatement(Loc(), TOKforeach,
+        new Parameter(0, NULL, Id::p, NULL),
+        new IntegerExp(Loc(), 0, Type::tsize_t),
+        new ArrayLengthExp(Loc(), new IdentifierExp(Loc(), p->ident)),
+        new ExpStatement(Loc(), loopbody),
+        Loc());
+    //printf("%s\n", s1->toChars());
+    Statement *s2 = new ReturnStatement(Loc(), new IdentifierExp(Loc(), p->ident));
+    //printf("s2: %s\n", s2->toChars());
+    Statement *fbody = new CompoundStatement(Loc(), s1, s2);
+
+    // Built-in array ops should be @trusted, pure, nothrow and nogc
+    StorageClass stc = STCtrusted | STCpure | STCnothrow | STCnogc;
+
+    /* Construct the function
+     */
+    TypeFunction *ftype = new TypeFunction(fparams, exp->type, 0, LINKc, stc);
+    //printf("fd: %s %s\n", ident->toChars(), ftype->toChars());
+    FuncDeclaration *fd = new FuncDeclaration(Loc(), Loc(), ident, STCundefined, ftype);
+    fd->fbody = fbody;
+    fd->protection = Prot(PROTpublic);
+    fd->linkage = LINKc;
+    fd->isArrayOp = 1;
+
+    sc->_module->importedFrom->members->push(fd);
+
+    sc = sc->push();
+    sc->parent = sc->_module->importedFrom;
+    sc->stc = 0;
+    sc->linkage = LINKc;
+    fd->semantic(sc);
+    fd->semantic2(sc);
+    unsigned errors = global.startGagging();
+    fd->semantic3(sc);
+    if (global.endGagging(errors))
+    {
+        fd->type = Type::terror;
+        fd->errors = true;
+        fd->fbody = NULL;
+    }
+    sc->pop();
+
+    return fd;
+}
+
+/**********************************************
+ * Check that there are no uses of arrays without [].
+ */
+bool isArrayOpValid(Expression *e)
+{
+    if (e->op == TOKslice)
+        return true;
+    if (e->op == TOKarrayliteral)
+    {
+        Type *t = e->type->toBasetype();
+        while (t->ty == Tarray || t->ty == Tsarray)
+            t = t->nextOf()->toBasetype();
+        return (t->ty != Tvoid);
+    }
+    Type *tb = e->type->toBasetype();
+    if (tb->ty == Tarray || tb->ty == Tsarray)
+    {
+        if (isUnaArrayOp(e->op))
+        {
+             return isArrayOpValid(((UnaExp *)e)->e1);
+        }
+        if (isBinArrayOp(e->op) ||
+            isBinAssignArrayOp(e->op) ||
+            e->op == TOKassign)
+        {
+            BinExp *be = (BinExp *)e;
+            return isArrayOpValid(be->e1) && isArrayOpValid(be->e2);
+        }
+        if (e->op == TOKconstruct)
+        {
+            BinExp *be = (BinExp *)e;
+            return be->e1->op == TOKslice && isArrayOpValid(be->e2);
+        }
+        if (e->op == TOKcall)
+        {
+             return false; // TODO: Decide if [] is required after arrayop calls.
+        }
+        else
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool isNonAssignmentArrayOp(Expression *e)
+{
+    if (e->op == TOKslice)
+        return isNonAssignmentArrayOp(((SliceExp *)e)->e1);
+
+    Type *tb = e->type->toBasetype();
+    if (tb->ty == Tarray || tb->ty == Tsarray)
+    {
+        return (isUnaArrayOp(e->op) || isBinArrayOp(e->op));
+    }
+    return false;
+}
+
+bool checkNonAssignmentArrayOp(Expression *e, bool suggestion)
+{
+    if (isNonAssignmentArrayOp(e))
+    {
+        const char *s = "";
+        if (suggestion)
+            s = " (possible missing [])";
+        e->error("array operation %s without destination memory not allowed%s", e->toChars(), s);
+        return true;
+    }
+    return false;
+}
+
+/***********************************
+ * Construct the array operation expression.
+ */
+
+Expression *arrayOp(BinExp *e, Scope *sc)
+{
+    //printf("BinExp::arrayOp() %s\n", toChars());
+
+    Type *tb = e->type->toBasetype();
+    assert(tb->ty == Tarray || tb->ty == Tsarray);
+    Type *tbn = tb->nextOf()->toBasetype();
+    if (tbn->ty == Tvoid)
+    {
+        e->error("cannot perform array operations on void[] arrays");
+        return new ErrorExp();
+    }
+    if (!isArrayOpValid(e))
+    {
+        e->error("invalid array operation %s (possible missing [])", e->toChars());
+        return new ErrorExp();
+    }
+
+    Expressions *arguments = new Expressions();
+
+    /* The expression to generate an array operation for is mangled
+     * into a name to use as the array operation function name.
+     * Mangle in the operands and operators in RPN order, and type.
+     */
+    OutBuffer buf;
+    buf.writestring("_array");
+    buildArrayIdent(e, &buf, arguments);
+    buf.writeByte('_');
+
+    /* Append deco of array element type
+     */
+    buf.writestring(e->type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
+
+    char *name = buf.peekString();
+    Identifier *ident = Identifier::idPool(name);
+
+    FuncDeclaration **pFd = (FuncDeclaration **)dmd_aaGet(&arrayfuncs, (void *)ident);
+    FuncDeclaration *fd = *pFd;
+
+    if (!fd)
+        fd = buildArrayOp(ident, e, sc, e->loc);
+
+    if (fd && fd->errors)
+    {
+        const char *fmt;
+        if (tbn->ty == Tstruct || tbn->ty == Tclass)
+            fmt = "invalid array operation '%s' because %s doesn't support necessary arithmetic operations";
+        else if (!tbn->isscalar())
+            fmt = "invalid array operation '%s' because %s is not a scalar type";
+        else
+            fmt = "invalid array operation '%s' for element type %s";
+
+        e->error(fmt, e->toChars(), tbn->toChars());
+        return new ErrorExp();
+    }
+
+    *pFd = fd;
+
+    Expression *ev = new VarExp(e->loc, fd);
+    Expression *ec = new CallExp(e->loc, ev, arguments);
+
+    return semantic(ec, sc);
+}
+
+Expression *arrayOp(BinAssignExp *e, Scope *sc)
+{
+    //printf("BinAssignExp::arrayOp() %s\n", toChars());
+
+    /* Check that the elements of e1 can be assigned to
+     */
+    Type *tn = e->e1->type->toBasetype()->nextOf();
+
+    if (tn && (!tn->isMutable() || !tn->isAssignable()))
+    {
+        e->error("slice %s is not mutable", e->e1->toChars());
+        return new ErrorExp();
+    }
+    if (e->e1->op == TOKarrayliteral)
+    {
+        return e->e1->modifiableLvalue(sc, e->e1);
+    }
+
+    return arrayOp((BinExp *)e, sc);
+}
+
+/******************************************
+ * Construct the identifier for the array operation function,
+ * and build the argument list to pass to it.
+ */
+
+void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments)
+{
+    class BuildArrayIdentVisitor : public Visitor
+    {
+        OutBuffer *buf;
+        Expressions *arguments;
+    public:
+        BuildArrayIdentVisitor(OutBuffer *buf, Expressions *arguments)
+            : buf(buf), arguments(arguments)
+        {
+        }
+
+        void visit(Expression *e)
+        {
+            buf->writestring("Exp");
+            arguments->shift(e);
+        }
+
+        void visit(CastExp *e)
+        {
+            Type *tb = e->type->toBasetype();
+            if (tb->ty == Tarray || tb->ty == Tsarray)
+            {
+                e->e1->accept(this);
+            }
+            else
+                visit((Expression *)e);
+        }
+
+        void visit(ArrayLiteralExp *e)
+        {
+            buf->writestring("Slice");
+            arguments->shift(e);
+        }
+
+        void visit(SliceExp *e)
+        {
+            buf->writestring("Slice");
+            arguments->shift(e);
+        }
+
+        void visit(AssignExp *e)
+        {
+            /* Evaluate assign expressions right to left
+             */
+            e->e2->accept(this);
+            e->e1->accept(this);
+            buf->writestring("Assign");
+        }
+
+        void visit(BinAssignExp *e)
+        {
+            /* Evaluate assign expressions right to left
+             */
+            e->e2->accept(this);
+            e->e1->accept(this);
+            const char *s;
+            switch(e->op)
+            {
+            case TOKaddass: s = "Addass"; break;
+            case TOKminass: s = "Minass"; break;
+            case TOKmulass: s = "Mulass"; break;
+            case TOKdivass: s = "Divass"; break;
+            case TOKmodass: s = "Modass"; break;
+            case TOKxorass: s = "Xorass"; break;
+            case TOKandass: s = "Andass"; break;
+            case TOKorass:  s = "Orass";  break;
+            case TOKpowass: s = "Powass"; break;
+            default: assert(0);
+            }
+            buf->writestring(s);
+        }
+
+        void visit(NegExp *e)
+        {
+            e->e1->accept(this);
+            buf->writestring("Neg");
+        }
+
+        void visit(ComExp *e)
+        {
+            e->e1->accept(this);
+            buf->writestring("Com");
+        }
+
+        void visit(BinExp *e)
+        {
+            /* Evaluate assign expressions left to right
+             */
+            const char *s = NULL;
+            switch(e->op)
+            {
+            case TOKadd: s = "Add"; break;
+            case TOKmin: s = "Min"; break;
+            case TOKmul: s = "Mul"; break;
+            case TOKdiv: s = "Div"; break;
+            case TOKmod: s = "Mod"; break;
+            case TOKxor: s = "Xor"; break;
+            case TOKand: s = "And"; break;
+            case TOKor:  s = "Or";  break;
+            case TOKpow: s = "Pow"; break;
+            default: break;
+            }
+            if (s)
+            {
+                Type *tb = e->type->toBasetype();
+                Type *t1 = e->e1->type->toBasetype();
+                Type *t2 = e->e2->type->toBasetype();
+                e->e1->accept(this);
+                if (t1->ty == Tarray &&
+                    (t2->ty == Tarray && !t1->equivalent(tb) ||
+                     t2->ty != Tarray && !t1->nextOf()->equivalent(e->e2->type)))
+                {
+                    // Bugzilla 12780: if A is narrower than B
+                    //  A[] op B[]
+                    //  A[] op B
+                    buf->writestring("Of");
+                    buf->writestring(t1->nextOf()->mutableOf()->deco);
+                }
+                e->e2->accept(this);
+                if (t2->ty == Tarray &&
+                    (t1->ty == Tarray && !t2->equivalent(tb) ||
+                     t1->ty != Tarray && !t2->nextOf()->equivalent(e->e1->type)))
+                {
+                    // Bugzilla 12780: if B is narrower than A:
+                    //  A[] op B[]
+                    //  A op B[]
+                    buf->writestring("Of");
+                    buf->writestring(t2->nextOf()->mutableOf()->deco);
+                }
+                buf->writestring(s);
+            }
+            else
+                visit((Expression *)e);
+        }
+    };
+
+    BuildArrayIdentVisitor v(buf, arguments);
+    e->accept(&v);
+}
+
+/******************************************
+ * Construct the inner loop for the array operation function,
+ * and build the parameter list.
+ */
+
+Expression *buildArrayLoop(Expression *e, Parameters *fparams)
+{
+    class BuildArrayLoopVisitor : public Visitor
+    {
+        Parameters *fparams;
+        Expression *result;
+
+    public:
+        BuildArrayLoopVisitor(Parameters *fparams)
+            : fparams(fparams), result(NULL)
+        {
+        }
+
+        void visit(Expression *e)
+        {
+            Identifier *id = Identifier::generateId("c", fparams->dim);
+            Parameter *param = new Parameter(0, e->type, id, NULL);
+            fparams->shift(param);
+            result = new IdentifierExp(Loc(), id);
+        }
+
+        void visit(CastExp *e)
+        {
+            Type *tb = e->type->toBasetype();
+            if (tb->ty == Tarray || tb->ty == Tsarray)
+            {
+                e->e1->accept(this);
+            }
+            else
+                visit((Expression *)e);
+        }
+
+        void visit(ArrayLiteralExp *e)
+        {
+            Identifier *id = Identifier::generateId("p", fparams->dim);
+            Parameter *param = new Parameter(STCconst, e->type, id, NULL);
+            fparams->shift(param);
+            Expression *ie = new IdentifierExp(Loc(), id);
+            Expression *index = new IdentifierExp(Loc(), Id::p);
+            result = new ArrayExp(Loc(), ie, index);
+        }
+
+        void visit(SliceExp *e)
+        {
+            Identifier *id = Identifier::generateId("p", fparams->dim);
+            Parameter *param = new Parameter(STCconst, e->type, id, NULL);
+            fparams->shift(param);
+            Expression *ie = new IdentifierExp(Loc(), id);
+            Expression *index = new IdentifierExp(Loc(), Id::p);
+            result = new ArrayExp(Loc(), ie, index);
+        }
+
+        void visit(AssignExp *e)
+        {
+            /* Evaluate assign expressions right to left
+             */
+            Expression *ex2 = buildArrayLoop(e->e2);
+            /* Need the cast because:
+             *   b = c + p[i];
+             * where b is a byte fails because (c + p[i]) is an int
+             * which cannot be implicitly cast to byte.
+             */
+            ex2 = new CastExp(Loc(), ex2, e->e1->type->nextOf());
+            Expression *ex1 = buildArrayLoop(e->e1);
+            Parameter *param = (*fparams)[0];
+            param->storageClass = 0;
+            result = new AssignExp(Loc(), ex1, ex2);
+        }
+
+        void visit(BinAssignExp *e)
+        {
+            /* Evaluate assign expressions right to left
+             */
+            Expression *ex2 = buildArrayLoop(e->e2);
+            Expression *ex1 = buildArrayLoop(e->e1);
+            Parameter *param = (*fparams)[0];
+            param->storageClass = 0;
+            switch(e->op)
+            {
+            case TOKaddass: result = new AddAssignExp(e->loc, ex1, ex2); return;
+            case TOKminass: result = new MinAssignExp(e->loc, ex1, ex2); return;
+            case TOKmulass: result = new MulAssignExp(e->loc, ex1, ex2); return;
+            case TOKdivass: result = new DivAssignExp(e->loc, ex1, ex2); return;
+            case TOKmodass: result = new ModAssignExp(e->loc, ex1, ex2); return;
+            case TOKxorass: result = new XorAssignExp(e->loc, ex1, ex2); return;
+            case TOKandass: result = new AndAssignExp(e->loc, ex1, ex2); return;
+            case TOKorass:  result = new OrAssignExp(e->loc, ex1, ex2); return;
+            case TOKpowass: result = new PowAssignExp(e->loc, ex1, ex2); return;
+            default:
+                assert(0);
+            }
+        }
+
+        void visit(NegExp *e)
+        {
+            Expression *ex1 = buildArrayLoop(e->e1);
+            result = new NegExp(Loc(), ex1);
+        }
+
+        void visit(ComExp *e)
+        {
+            Expression *ex1 = buildArrayLoop(e->e1);
+            result = new ComExp(Loc(), ex1);
+        }
+
+        void visit(BinExp *e)
+        {
+            if (isBinArrayOp(e->op))
+            {
+                /* Evaluate assign expressions left to right
+                 */
+                BinExp *be = (BinExp *)e->copy();
+                be->e1 = buildArrayLoop(be->e1);
+                be->e2 = buildArrayLoop(be->e2);
+                be->type = NULL;
+                result = be;
+                return;
+            }
+            else
+            {
+                visit((Expression *)e);
+                return;
+            }
+        }
+
+        Expression *buildArrayLoop(Expression *e)
+        {
+            e->accept(this);
+            return result;
+        }
+    };
+
+    BuildArrayLoopVisitor v(fparams);
+    return v.buildArrayLoop(e);
+}
+
+/***********************************************
+ * Test if expression is a unary array op.
+ */
+
+bool isUnaArrayOp(TOK op)
+{
+    switch (op)
+    {
+    case TOKneg:
+    case TOKtilde:
+        return true;
+    default:
+        break;
+    }
+    return false;
+}
+
+/***********************************************
+ * Test if expression is a binary array op.
+ */
+
+bool isBinArrayOp(TOK op)
+{
+    switch (op)
+    {
+    case TOKadd:
+    case TOKmin:
+    case TOKmul:
+    case TOKdiv:
+    case TOKmod:
+    case TOKxor:
+    case TOKand:
+    case TOKor:
+    case TOKpow:
+        return true;
+    default:
+        break;
+    }
+    return false;
+}
+
+/***********************************************
+ * Test if expression is a binary assignment array op.
+ */
+
+bool isBinAssignArrayOp(TOK op)
+{
+    switch (op)
+    {
+    case TOKaddass:
+    case TOKminass:
+    case TOKmulass:
+    case TOKdivass:
+    case TOKmodass:
+    case TOKxorass:
+    case TOKandass:
+    case TOKorass:
+    case TOKpowass:
+        return true;
+    default:
+        break;
+    }
+    return false;
+}
+
+/***********************************************
+ * Test if operand is a valid array op operand.
+ */
+
+bool isArrayOpOperand(Expression *e)
+{
+    //printf("Expression::isArrayOpOperand() %s\n", e->toChars());
+    if (e->op == TOKslice)
+        return true;
+    if (e->op == TOKarrayliteral)
+    {
+        Type *t = e->type->toBasetype();
+        while (t->ty == Tarray || t->ty == Tsarray)
+            t = t->nextOf()->toBasetype();
+        return (t->ty != Tvoid);
+    }
+    Type *tb = e->type->toBasetype();
+    if (tb->ty == Tarray)
+    {
+        return (isUnaArrayOp(e->op) ||
+                isBinArrayOp(e->op) ||
+                isBinAssignArrayOp(e->op) ||
+                e->op == TOKassign);
+    }
+    return false;
+}
diff --git a/gcc/d/dfrontend/arraytypes.h b/gcc/d/dfrontend/arraytypes.h
new file mode 100644
index 00000000000..c5a7d190184
--- /dev/null
+++ b/gcc/d/dfrontend/arraytypes.h
@@ -0,0 +1,71 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 2006-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/arraytypes.h
+ */
+
+#ifndef DMD_ARRAYTYPES_H
+#define DMD_ARRAYTYPES_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+
+#include "root.h"
+
+typedef Array<class TemplateParameter *> TemplateParameters;
+
+typedef Array<class Expression *> Expressions;
+
+typedef Array<class Statement *> Statements;
+
+typedef Array<struct BaseClass *> BaseClasses;
+
+typedef Array<class ClassDeclaration *> ClassDeclarations;
+
+typedef Array<class Dsymbol *> Dsymbols;
+
+typedef Array<class RootObject *> Objects;
+
+typedef Array<class FuncDeclaration *> FuncDeclarations;
+
+typedef Array<class Parameter *> Parameters;
+
+typedef Array<class Identifier *> Identifiers;
+
+typedef Array<class Initializer *> Initializers;
+
+typedef Array<class VarDeclaration *> VarDeclarations;
+
+typedef Array<class Type *> Types;
+typedef Array<class Catch *> Catches;
+
+typedef Array<class StaticDtorDeclaration *> StaticDtorDeclarations;
+
+typedef Array<class SharedStaticDtorDeclaration *> SharedStaticDtorDeclarations;
+
+typedef Array<class AliasDeclaration *> AliasDeclarations;
+
+typedef Array<class Module *> Modules;
+
+typedef Array<struct File *> Files;
+
+typedef Array<class CaseStatement *> CaseStatements;
+
+typedef Array<class ScopeStatement *> ScopeStatements;
+
+typedef Array<class GotoCaseStatement *> GotoCaseStatements;
+
+typedef Array<class ReturnStatement *> ReturnStatements;
+
+typedef Array<class GotoStatement *> GotoStatements;
+
+typedef Array<class TemplateInstance *> TemplateInstances;
+
+#endif
diff --git a/gcc/d/dfrontend/attrib.c b/gcc/d/dfrontend/attrib.c
new file mode 100644
index 00000000000..f36fd87b445
--- /dev/null
+++ b/gcc/d/dfrontend/attrib.c
@@ -0,0 +1,1599 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/attrib.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>                     // memcpy()
+
+#include "rmem.h"
+
+#include "init.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "cond.h"
+#include "scope.h"
+#include "id.h"
+#include "expression.h"
+#include "dsymbol.h"
+#include "aggregate.h"
+#include "module.h"
+#include "parse.h"
+#include "target.h"
+#include "template.h"
+#include "utf.h"
+#include "mtype.h"
+
+bool definitelyValueParameter(Expression *e);
+Expression *semantic(Expression *e, Scope *sc);
+
+/********************************* AttribDeclaration ****************************/
+
+AttribDeclaration::AttribDeclaration(Dsymbols *decl)
+        : Dsymbol()
+{
+    this->decl = decl;
+}
+
+Dsymbols *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sds)
+{
+    return decl;
+}
+
+int AttribDeclaration::apply(Dsymbol_apply_ft_t fp, void *param)
+{
+    Dsymbols *d = include(_scope, NULL);
+
+    if (d)
+    {
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (*d)[i];
+            if (s)
+            {
+                if (s->apply(fp, param))
+                    return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+/****************************************
+ * Create a new scope if one or more given attributes
+ * are different from the sc's.
+ * If the returned scope != sc, the caller should pop
+ * the scope after it used.
+ */
+Scope *AttribDeclaration::createNewScope(Scope *sc,
+        StorageClass stc, LINK linkage, CPPMANGLE cppmangle, Prot protection,
+        int explicitProtection, AlignDeclaration *aligndecl, PINLINE inlining)
+{
+    Scope *sc2 = sc;
+    if (stc != sc->stc ||
+        linkage != sc->linkage ||
+        cppmangle != sc->cppmangle ||
+        !protection.isSubsetOf(sc->protection) ||
+        explicitProtection != sc->explicitProtection ||
+        aligndecl != sc->aligndecl ||
+        inlining != sc->inlining)
+    {
+        // create new one for changes
+        sc2 = sc->copy();
+        sc2->stc = stc;
+        sc2->linkage = linkage;
+        sc2->cppmangle = cppmangle;
+        sc2->protection = protection;
+        sc2->explicitProtection = explicitProtection;
+        sc2->aligndecl = aligndecl;
+        sc2->inlining = inlining;
+    }
+    return sc2;
+}
+
+/****************************************
+ * A hook point to supply scope for members.
+ * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
+ */
+Scope *AttribDeclaration::newScope(Scope *sc)
+{
+    return sc;
+}
+
+void AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+    Dsymbols *d = include(sc, sds);
+
+    if (d)
+    {
+        Scope *sc2 = newScope(sc);
+
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (*d)[i];
+            //printf("\taddMember %s to %s\n", s->toChars(), sds->toChars());
+            s->addMember(sc2, sds);
+        }
+
+        if (sc2 != sc)
+            sc2->pop();
+    }
+}
+
+void AttribDeclaration::setScope(Scope *sc)
+{
+    Dsymbols *d = include(sc, NULL);
+
+    //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d);
+    if (d)
+    {
+        Scope *sc2 = newScope(sc);
+
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (*d)[i];
+            s->setScope(sc2);
+        }
+
+        if (sc2 != sc)
+            sc2->pop();
+    }
+}
+
+void AttribDeclaration::importAll(Scope *sc)
+{
+    Dsymbols *d = include(sc, NULL);
+
+    //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
+    if (d)
+    {
+        Scope *sc2 = newScope(sc);
+
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (*d)[i];
+            s->importAll(sc2);
+        }
+
+        if (sc2 != sc)
+            sc2->pop();
+    }
+}
+
+void AttribDeclaration::semantic(Scope *sc)
+{
+    Dsymbols *d = include(sc, NULL);
+
+    //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d);
+    if (d)
+    {
+        Scope *sc2 = newScope(sc);
+
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (*d)[i];
+            s->semantic(sc2);
+        }
+
+        if (sc2 != sc)
+            sc2->pop();
+    }
+}
+
+void AttribDeclaration::semantic2(Scope *sc)
+{
+    Dsymbols *d = include(sc, NULL);
+
+    if (d)
+    {
+        Scope *sc2 = newScope(sc);
+
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (*d)[i];
+            s->semantic2(sc2);
+        }
+
+        if (sc2 != sc)
+            sc2->pop();
+    }
+}
+
+void AttribDeclaration::semantic3(Scope *sc)
+{
+    Dsymbols *d = include(sc, NULL);
+
+    if (d)
+    {
+        Scope *sc2 = newScope(sc);
+
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (*d)[i];
+            s->semantic3(sc2);
+        }
+
+        if (sc2 != sc)
+            sc2->pop();
+    }
+}
+
+void AttribDeclaration::addComment(const utf8_t *comment)
+{
+    //printf("AttribDeclaration::addComment %s\n", comment);
+    if (comment)
+    {
+        Dsymbols *d = include(NULL, NULL);
+
+        if (d)
+        {
+            for (size_t i = 0; i < d->dim; i++)
+            {
+                Dsymbol *s = (*d)[i];
+                //printf("AttribDeclaration::addComment %s\n", s->toChars());
+                s->addComment(comment);
+            }
+        }
+    }
+}
+
+void AttribDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
+{
+    Dsymbols *d = include(NULL, NULL);
+
+    if (d)
+    {
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (*d)[i];
+            s->setFieldOffset(ad, poffset, isunion);
+        }
+    }
+}
+
+bool AttribDeclaration::hasPointers()
+{
+    Dsymbols *d = include(NULL, NULL);
+
+    if (d)
+    {
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (*d)[i];
+            if (s->hasPointers())
+                return true;
+        }
+    }
+    return false;
+}
+
+bool AttribDeclaration::hasStaticCtorOrDtor()
+{
+    Dsymbols *d = include(NULL, NULL);
+
+    if (d)
+    {
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (*d)[i];
+            if (s->hasStaticCtorOrDtor())
+                return true;
+        }
+    }
+    return false;
+}
+
+const char *AttribDeclaration::kind() const
+{
+    return "attribute";
+}
+
+bool AttribDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
+{
+    Dsymbols *d = include(NULL, NULL);
+
+    return Dsymbol::oneMembers(d, ps, ident);
+}
+
+void AttribDeclaration::checkCtorConstInit()
+{
+    Dsymbols *d = include(NULL, NULL);
+
+    if (d)
+    {
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (*d)[i];
+            s->checkCtorConstInit();
+        }
+    }
+}
+
+/****************************************
+ */
+
+void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses)
+{
+    Dsymbols *d = include(NULL, NULL);
+
+    if (d)
+    {
+        for (size_t i = 0; i < d->dim; i++)
+        {
+            Dsymbol *s = (*d)[i];
+            s->addLocalClass(aclasses);
+        }
+    }
+}
+
+/************************* StorageClassDeclaration ****************************/
+
+StorageClassDeclaration::StorageClassDeclaration(StorageClass stc, Dsymbols *decl)
+        : AttribDeclaration(decl)
+{
+    this->stc = stc;
+}
+
+Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    return new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl));
+}
+
+bool StorageClassDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
+{
+    bool t = Dsymbol::oneMembers(decl, ps, ident);
+    if (t && *ps)
+    {
+        /* This is to deal with the following case:
+         * struct Tick {
+         *   template to(T) { const T to() { ... } }
+         * }
+         * For eponymous function templates, the 'const' needs to get attached to 'to'
+         * before the semantic analysis of 'to', so that template overloading based on the
+         * 'this' pointer can be successful.
+         */
+
+        FuncDeclaration *fd = (*ps)->isFuncDeclaration();
+        if (fd)
+        {
+            /* Use storage_class2 instead of storage_class otherwise when we do .di generation
+             * we'll wind up with 'const const' rather than 'const'.
+             */
+            /* Don't think we need to worry about mutually exclusive storage classes here
+             */
+            fd->storage_class2 |= stc;
+        }
+    }
+    return t;
+}
+
+Scope *StorageClassDeclaration::newScope(Scope *sc)
+{
+    StorageClass scstc = sc->stc;
+
+    /* These sets of storage classes are mutually exclusive,
+     * so choose the innermost or most recent one.
+     */
+    if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest))
+        scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest);
+    if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared))
+        scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared);
+    if (stc & (STCconst | STCimmutable | STCmanifest))
+        scstc &= ~(STCconst | STCimmutable | STCmanifest);
+    if (stc & (STCgshared | STCshared | STCtls))
+        scstc &= ~(STCgshared | STCshared | STCtls);
+    if (stc & (STCsafe | STCtrusted | STCsystem))
+        scstc &= ~(STCsafe | STCtrusted | STCsystem);
+    scstc |= stc;
+    //printf("scstc = x%llx\n", scstc);
+
+    return createNewScope(sc, scstc, sc->linkage, sc->cppmangle,
+        sc->protection, sc->explicitProtection, sc->aligndecl,
+        sc->inlining);
+}
+
+/********************************* DeprecatedDeclaration ****************************/
+
+DeprecatedDeclaration::DeprecatedDeclaration(Expression *msg, Dsymbols *decl)
+        : StorageClassDeclaration(STCdeprecated, decl)
+{
+    this->msg = msg;
+    this->msgstr = NULL;
+}
+
+Dsymbol *DeprecatedDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    return new DeprecatedDeclaration(msg->syntaxCopy(), Dsymbol::arraySyntaxCopy(decl));
+}
+
+/**
+ * Provides a new scope with `STCdeprecated` and `Scope.depdecl` set
+ *
+ * Calls `StorageClassDeclaration.newScope` (as it must be called or copied
+ * in any function overriding `newScope`), then set the `Scope`'s depdecl.
+ *
+ * Returns:
+ *   Always a new scope, to use for this `DeprecatedDeclaration`'s members.
+ */
+Scope *DeprecatedDeclaration::newScope(Scope *sc)
+{
+    Scope *scx = StorageClassDeclaration::newScope(sc);
+    // The enclosing scope is deprecated as well
+    if (scx == sc)
+        scx = sc->push();
+    scx->depdecl = this;
+    return scx;
+}
+
+void DeprecatedDeclaration::setScope(Scope *sc)
+{
+    //printf("DeprecatedDeclaration::setScope() %p\n", this);
+    if (decl)
+        Dsymbol::setScope(sc); // for forward reference
+    return AttribDeclaration::setScope(sc);
+}
+
+/**
+ * Run the DeprecatedDeclaration's semantic2 phase then its members.
+ *
+ * The message set via a `DeprecatedDeclaration` can be either of:
+ * - a string literal
+ * - an enum
+ * - a static immutable
+ * So we need to call ctfe to resolve it.
+ * Afterward forwards to the members' semantic2.
+ */
+void DeprecatedDeclaration::semantic2(Scope *sc)
+{
+    getMessage();
+    StorageClassDeclaration::semantic2(sc);
+}
+
+const char *DeprecatedDeclaration::getMessage()
+{
+    if (Scope *sc = _scope)
+    {
+        _scope = NULL;
+
+        sc = sc->startCTFE();
+        msg = ::semantic(msg, sc);
+        msg = resolveProperties(sc, msg);
+        sc = sc->endCTFE();
+        msg = msg->ctfeInterpret();
+
+        if (StringExp *se = msg->toStringExp())
+            msgstr = (char *)se->string;
+        else
+            msg->error("compile time constant expected, not '%s'", msg->toChars());
+    }
+    return msgstr;
+}
+
+/********************************* LinkDeclaration ****************************/
+
+LinkDeclaration::LinkDeclaration(LINK p, Dsymbols *decl)
+        : AttribDeclaration(decl)
+{
+    //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl);
+    linkage = (p == LINKsystem) ? Target::systemLinkage() : p;
+}
+
+LinkDeclaration *LinkDeclaration::create(LINK p, Dsymbols *decl)
+{
+    return new LinkDeclaration(p, decl);
+}
+
+Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    return new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl));
+}
+
+Scope *LinkDeclaration::newScope(Scope *sc)
+{
+    return createNewScope(sc, sc->stc, this->linkage, sc->cppmangle,
+        sc->protection, sc->explicitProtection, sc->aligndecl,
+        sc->inlining);
+}
+
+const char *LinkDeclaration::toChars()
+{
+    return (char *)"extern ()";
+}
+
+/********************************* CPPMangleDeclaration ****************************/
+
+CPPMangleDeclaration::CPPMangleDeclaration(CPPMANGLE p, Dsymbols *decl)
+        : AttribDeclaration(decl)
+{
+    //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", p, decl);
+    cppmangle = p;
+}
+
+Dsymbol *CPPMangleDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    return new CPPMangleDeclaration(cppmangle, Dsymbol::arraySyntaxCopy(decl));
+}
+
+Scope *CPPMangleDeclaration::newScope(Scope *sc)
+{
+    return createNewScope(sc, sc->stc, LINKcpp, this->cppmangle,
+        sc->protection, sc->explicitProtection, sc->aligndecl,
+        sc->inlining);
+}
+
+const char *CPPMangleDeclaration::toChars()
+{
+    return (char *)"extern ()";
+}
+
+/********************************* ProtDeclaration ****************************/
+
+/**
+ * Params:
+ *  loc = source location of attribute token
+ *  p = protection attribute data
+ *  decl = declarations which are affected by this protection attribute
+ */
+ProtDeclaration::ProtDeclaration(Loc loc, Prot p, Dsymbols *decl)
+        : AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->protection = p;
+    this->pkg_identifiers = NULL;
+    //printf("decl = %p\n", decl);
+}
+
+/**
+ * Params:
+ *  loc = source location of attribute token
+ *  pkg_identifiers = list of identifiers for a qualified package name
+ *  decl = declarations which are affected by this protection attribute
+ */
+ProtDeclaration::ProtDeclaration(Loc loc, Identifiers* pkg_identifiers, Dsymbols *decl)
+        : AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->protection.kind = PROTpackage;
+    this->protection.pkg  = NULL;
+    this->pkg_identifiers = pkg_identifiers;
+}
+
+Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    if (protection.kind == PROTpackage)
+        return new ProtDeclaration(this->loc, pkg_identifiers, Dsymbol::arraySyntaxCopy(decl));
+    else
+        return new ProtDeclaration(this->loc, protection, Dsymbol::arraySyntaxCopy(decl));
+}
+
+Scope *ProtDeclaration::newScope(Scope *sc)
+{
+    if (pkg_identifiers)
+        semantic(sc);
+    return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle,
+        this->protection, 1, sc->aligndecl,
+        sc->inlining);
+}
+
+void ProtDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+    if (pkg_identifiers)
+    {
+        Dsymbol* tmp;
+        Package::resolve(pkg_identifiers, &tmp, NULL);
+        protection.pkg = tmp ? tmp->isPackage() : NULL;
+        pkg_identifiers = NULL;
+    }
+
+    if (protection.kind == PROTpackage && protection.pkg && sc->_module)
+    {
+        Module *m = sc->_module;
+        Package* pkg = m->parent ? m->parent->isPackage() : NULL;
+        if (!pkg || !protection.pkg->isAncestorPackageOf(pkg))
+            error("does not bind to one of ancestor packages of module '%s'",
+               m->toPrettyChars(true));
+    }
+
+    return AttribDeclaration::addMember(sc, sds);
+}
+
+const char *ProtDeclaration::kind() const
+{
+    return "protection attribute";
+}
+
+const char *ProtDeclaration::toPrettyChars(bool)
+{
+    assert(protection.kind > PROTundefined);
+
+    OutBuffer buf;
+    buf.writeByte('\'');
+    protectionToBuffer(&buf, protection);
+    buf.writeByte('\'');
+    return buf.extractString();
+}
+
+/********************************* AlignDeclaration ****************************/
+
+AlignDeclaration::AlignDeclaration(Loc loc, Expression *ealign, Dsymbols *decl)
+        : AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->ealign = ealign;
+    this->salign = STRUCTALIGN_DEFAULT;
+}
+
+Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    return new AlignDeclaration(loc,
+        ealign->syntaxCopy(), Dsymbol::arraySyntaxCopy(decl));
+}
+
+Scope *AlignDeclaration::newScope(Scope *sc)
+{
+    return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle,
+        sc->protection, sc->explicitProtection, this,
+        sc->inlining);
+}
+
+void AlignDeclaration::setScope(Scope *sc)
+{
+    //printf("AlignDeclaration::setScope() %p\n", this);
+    if (ealign && decl)
+        Dsymbol::setScope(sc); // for forward reference
+    return AttribDeclaration::setScope(sc);
+}
+
+void AlignDeclaration::semantic2(Scope *sc)
+{
+    getAlignment();
+    AttribDeclaration::semantic2(sc);
+}
+
+static structalign_t errorPositiveInteger(Loc loc, Expression *ealign)
+{
+    error(loc, "positive integer expected, not %s", ealign->toChars());
+    return STRUCTALIGN_DEFAULT;
+}
+
+structalign_t AlignDeclaration::getAlignment()
+{
+    if (!ealign)
+        return STRUCTALIGN_DEFAULT;
+
+    if (Scope *sc = _scope)
+    {
+        _scope = NULL;
+
+        sc = sc->startCTFE();
+        ealign = ::semantic(ealign, sc);
+        ealign = resolveProperties(sc, ealign);
+        sc = sc->endCTFE();
+
+        if (ealign->op == TOKerror)
+            return STRUCTALIGN_DEFAULT;
+        if (!ealign->type)
+            return errorPositiveInteger(loc, ealign);
+        Type *tb = ealign->type->toBasetype();
+        if (!tb->isintegral())
+            return errorPositiveInteger(loc, ealign);
+        if (tb->ty == Tchar || tb->ty == Twchar || tb->ty == Tdchar || tb->ty == Tbool)
+            return errorPositiveInteger(loc, ealign);
+
+        ealign = ealign->ctfeInterpret();
+        if (ealign->op == TOKerror)
+            return STRUCTALIGN_DEFAULT;
+
+        sinteger_t n = ealign->toInteger();
+        if (n < 1 || STRUCTALIGN_DEFAULT < n)
+            return errorPositiveInteger(loc, ealign);
+
+        if (n & (n - 1))
+        {
+            ::error(loc, "alignment must be a power of 2, not %u", (structalign_t)n);
+            return STRUCTALIGN_DEFAULT;
+        }
+
+        salign = (structalign_t)n;
+    }
+    return salign;
+}
+
+/********************************* AnonDeclaration ****************************/
+
+AnonDeclaration::AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl)
+        : AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->isunion = isunion;
+    this->sem = 0;
+    this->anonoffset = 0;
+    this->anonstructsize = 0;
+    this->anonalignsize = 0;
+}
+
+Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    return new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl));
+}
+
+void AnonDeclaration::setScope(Scope *sc)
+{
+    //printf("AnonDeclaration::setScope() %p\n", this);
+    if (decl)
+        Dsymbol::setScope(sc);
+    AttribDeclaration::setScope(sc);
+}
+
+void AnonDeclaration::semantic(Scope *sc)
+{
+    //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
+
+    assert(sc->parent);
+
+    Dsymbol *p = sc->parent->pastMixin();
+    AggregateDeclaration *ad = p->isAggregateDeclaration();
+    if (!ad)
+    {
+        ::error(loc, "%s can only be a part of an aggregate, not %s %s",
+            kind(), p->kind(), p->toChars());
+        return;
+    }
+
+    if (decl)
+    {
+        sc = sc->push();
+        sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared);
+        sc->inunion = isunion;
+        sc->flags = 0;
+
+        for (size_t i = 0; i < decl->dim; i++)
+        {
+            Dsymbol *s = (*decl)[i];
+            s->semantic(sc);
+        }
+        sc = sc->pop();
+    }
+}
+
+void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
+{
+    //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
+
+    if (decl)
+    {
+        /* This works by treating an AnonDeclaration as an aggregate 'member',
+         * so in order to place that member we need to compute the member's
+         * size and alignment.
+         */
+
+        size_t fieldstart = ad->fields.dim;
+
+        /* Hackishly hijack ad's structsize and alignsize fields
+         * for use in our fake anon aggregate member.
+         */
+        unsigned savestructsize = ad->structsize;
+        unsigned savealignsize  = ad->alignsize;
+        ad->structsize = 0;
+        ad->alignsize = 0;
+
+        unsigned offset = 0;
+        for (size_t i = 0; i < decl->dim; i++)
+        {
+            Dsymbol *s = (*decl)[i];
+            s->setFieldOffset(ad, &offset, this->isunion);
+            if (this->isunion)
+                offset = 0;
+        }
+
+        /* Bugzilla 13613: If the fields in this->members had been already
+         * added in ad->fields, just update *poffset for the subsequent
+         * field offset calculation.
+         */
+        if (fieldstart == ad->fields.dim)
+        {
+            ad->structsize = savestructsize;
+            ad->alignsize  = savealignsize;
+            *poffset = ad->structsize;
+            return;
+        }
+
+        anonstructsize = ad->structsize;
+        anonalignsize  = ad->alignsize;
+        ad->structsize = savestructsize;
+        ad->alignsize  = savealignsize;
+
+        // 0 sized structs are set to 1 byte
+        // TODO: is this corect hebavior?
+        if (anonstructsize == 0)
+        {
+            anonstructsize = 1;
+            anonalignsize = 1;
+        }
+
+        assert(_scope);
+        structalign_t alignment = _scope->alignment();
+
+        /* Given the anon 'member's size and alignment,
+         * go ahead and place it.
+         */
+        anonoffset = AggregateDeclaration::placeField(
+                poffset,
+                anonstructsize, anonalignsize, alignment,
+                &ad->structsize, &ad->alignsize,
+                isunion);
+
+        // Add to the anon fields the base offset of this anonymous aggregate
+        //printf("anon fields, anonoffset = %d\n", anonoffset);
+        for (size_t i = fieldstart; i < ad->fields.dim; i++)
+        {
+            VarDeclaration *v = ad->fields[i];
+            //printf("\t[%d] %s %d\n", i, v->toChars(), v->offset);
+            v->offset += anonoffset;
+        }
+    }
+}
+
+const char *AnonDeclaration::kind() const
+{
+    return (isunion ? "anonymous union" : "anonymous struct");
+}
+
+/********************************* PragmaDeclaration ****************************/
+
+PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl)
+        : AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->ident = ident;
+    this->args = args;
+}
+
+Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
+    assert(!s);
+    return new PragmaDeclaration(loc, ident,
+        Expression::arraySyntaxCopy(args),
+        Dsymbol::arraySyntaxCopy(decl));
+}
+
+Scope *PragmaDeclaration::newScope(Scope *sc)
+{
+    if (ident == Id::Pinline)
+    {
+        PINLINE inlining = PINLINEdefault;
+        if (!args || args->dim == 0)
+            inlining = PINLINEdefault;
+        else if (args->dim != 1)
+        {
+            error("one boolean expression expected for pragma(inline), not %d", args->dim);
+            args->setDim(1);
+            (*args)[0] = new ErrorExp();
+        }
+        else
+        {
+            Expression *e = (*args)[0];
+
+            if (e->op != TOKint64 || !e->type->equals(Type::tbool))
+            {
+                if (e->op != TOKerror)
+                {
+                    error("pragma(inline, true or false) expected, not %s", e->toChars());
+                    (*args)[0] = new ErrorExp();
+                }
+            }
+            else if (e->isBool(true))
+                inlining = PINLINEalways;
+            else if (e->isBool(false))
+                inlining = PINLINEnever;
+        }
+
+        return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle,
+            sc->protection, sc->explicitProtection, sc->aligndecl,
+            inlining);
+    }
+    return sc;
+}
+
+static unsigned setMangleOverride(Dsymbol *s, char *sym)
+{
+    AttribDeclaration *ad = s->isAttribDeclaration();
+
+    if (ad)
+    {
+        Dsymbols *decls = ad->include(NULL, NULL);
+        unsigned nestedCount = 0;
+
+        if (decls && decls->dim)
+            for (size_t i = 0; i < decls->dim; ++i)
+                nestedCount += setMangleOverride((*decls)[i], sym);
+
+        return nestedCount;
+    }
+    else if (s->isFuncDeclaration() || s->isVarDeclaration())
+    {
+        s->isDeclaration()->mangleOverride = sym;
+        return 1;
+    }
+    else
+        return 0;
+}
+
+void PragmaDeclaration::semantic(Scope *sc)
+{
+    // Should be merged with PragmaStatement
+
+    //printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
+    if (ident == Id::msg)
+    {
+        if (args)
+        {
+            for (size_t i = 0; i < args->dim; i++)
+            {
+                Expression *e = (*args)[i];
+
+                sc = sc->startCTFE();
+                e = ::semantic(e, sc);
+                e = resolveProperties(sc, e);
+                sc = sc->endCTFE();
+
+                // pragma(msg) is allowed to contain types as well as expressions
+                e = ctfeInterpretForPragmaMsg(e);
+                if (e->op == TOKerror)
+                {
+                    errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars());
+                    return;
+                }
+                StringExp *se = e->toStringExp();
+                if (se)
+                {
+                    se = se->toUTF8(sc);
+                    fprintf(stderr, "%.*s", (int)se->len, (char *)se->string);
+                }
+                else
+                    fprintf(stderr, "%s", e->toChars());
+            }
+            fprintf(stderr, "\n");
+        }
+        goto Lnodecl;
+    }
+    else if (ident == Id::lib)
+    {
+        if (!args || args->dim != 1)
+            error("string expected for library name");
+        else
+        {
+            Expression *e = (*args)[0];
+
+            sc = sc->startCTFE();
+            e = ::semantic(e, sc);
+            e = resolveProperties(sc, e);
+            sc = sc->endCTFE();
+
+            e = e->ctfeInterpret();
+            (*args)[0] = e;
+            if (e->op == TOKerror)
+                goto Lnodecl;
+            StringExp *se = e->toStringExp();
+            if (!se)
+                error("string expected for library name, not '%s'", e->toChars());
+            else
+            {
+                char *name = (char *)mem.xmalloc(se->len + 1);
+                memcpy(name, se->string, se->len);
+                name[se->len] = 0;
+                if (global.params.verbose)
+                    fprintf(global.stdmsg, "library   %s\n", name);
+                if (global.params.moduleDeps && !global.params.moduleDepsFile)
+                {
+                    OutBuffer *ob = global.params.moduleDeps;
+                    Module *imod = sc->instantiatingModule();
+                    ob->writestring("depsLib ");
+                    ob->writestring(imod->toPrettyChars());
+                    ob->writestring(" (");
+                    escapePath(ob, imod->srcfile->toChars());
+                    ob->writestring(") : ");
+                    ob->writestring((char *) name);
+                    ob->writenl();
+                }
+                mem.xfree(name);
+            }
+        }
+        goto Lnodecl;
+    }
+    else if (ident == Id::startaddress)
+    {
+        if (!args || args->dim != 1)
+            error("function name expected for start address");
+        else
+        {
+            /* Bugzilla 11980:
+             * resolveProperties and ctfeInterpret call are not necessary.
+             */
+            Expression *e = (*args)[0];
+
+            sc = sc->startCTFE();
+            e = ::semantic(e, sc);
+            sc = sc->endCTFE();
+
+            (*args)[0] = e;
+            Dsymbol *sa = getDsymbol(e);
+            if (!sa || !sa->isFuncDeclaration())
+                error("function name expected for start address, not '%s'", e->toChars());
+        }
+        goto Lnodecl;
+    }
+    else if (ident == Id::Pinline)
+    {
+        goto Ldecl;
+    }
+    else if (ident == Id::mangle)
+    {
+        if (!args)
+            args = new Expressions();
+        if (args->dim != 1)
+        {
+            error("string expected for mangled name");
+            args->setDim(1);
+            (*args)[0] = new ErrorExp();    // error recovery
+            goto Ldecl;
+        }
+
+        Expression *e = (*args)[0];
+        e = ::semantic(e, sc);
+        e = e->ctfeInterpret();
+        (*args)[0] = e;
+        if (e->op == TOKerror)
+            goto Ldecl;
+
+        StringExp *se = e->toStringExp();
+        if (!se)
+        {
+            error("string expected for mangled name, not '%s'", e->toChars());
+            goto Ldecl;
+        }
+        if (!se->len)
+        {
+            error("zero-length string not allowed for mangled name");
+            goto Ldecl;
+        }
+        if (se->sz != 1)
+        {
+            error("mangled name characters can only be of type char");
+            goto Ldecl;
+        }
+
+#if 1
+        /* Note: D language specification should not have any assumption about backend
+         * implementation. Ideally pragma(mangle) can accept a string of any content.
+         *
+         * Therefore, this validation is compiler implementation specific.
+         */
+        for (size_t i = 0; i < se->len; )
+        {
+            utf8_t *p = (utf8_t *)se->string;
+            dchar_t c = p[i];
+            if (c < 0x80)
+            {
+                if (c >= 'A' && c <= 'Z' ||
+                    c >= 'a' && c <= 'z' ||
+                    c >= '0' && c <= '9' ||
+                    c != 0 && strchr("$%().:?@[]_", c))
+                {
+                    ++i;
+                    continue;
+                }
+                else
+                {
+                    error("char 0x%02x not allowed in mangled name", c);
+                    break;
+                }
+            }
+
+            if (const char* msg = utf_decodeChar((utf8_t *)se->string, se->len, &i, &c))
+            {
+                error("%s", msg);
+                break;
+            }
+
+            if (!isUniAlpha(c))
+            {
+                error("char 0x%04x not allowed in mangled name", c);
+                break;
+            }
+        }
+#endif
+    }
+    else if (global.params.ignoreUnsupportedPragmas)
+    {
+        if (global.params.verbose)
+        {
+            /* Print unrecognized pragmas
+             */
+            fprintf(global.stdmsg, "pragma    %s", ident->toChars());
+            if (args)
+            {
+                for (size_t i = 0; i < args->dim; i++)
+                {
+                    Expression *e = (*args)[i];
+
+                    sc = sc->startCTFE();
+                    e = ::semantic(e, sc);
+                    e = resolveProperties(sc, e);
+                    sc = sc->endCTFE();
+
+                    e = e->ctfeInterpret();
+                    if (i == 0)
+                        fprintf(global.stdmsg, " (");
+                    else
+                        fprintf(global.stdmsg, ",");
+                    fprintf(global.stdmsg, "%s", e->toChars());
+                }
+                if (args->dim)
+                    fprintf(global.stdmsg, ")");
+            }
+            fprintf(global.stdmsg, "\n");
+        }
+        goto Lnodecl;
+    }
+    else
+        error("unrecognized pragma(%s)", ident->toChars());
+
+Ldecl:
+    if (decl)
+    {
+        Scope *sc2 = newScope(sc);
+
+        for (size_t i = 0; i < decl->dim; i++)
+        {
+            Dsymbol *s = (*decl)[i];
+
+            s->semantic(sc2);
+
+            if (ident == Id::mangle)
+            {
+                assert(args && args->dim == 1);
+                if (StringExp *se = (*args)[0]->toStringExp())
+                {
+                    char *name = (char *)mem.xmalloc(se->len + 1);
+                    memcpy(name, se->string, se->len);
+                    name[se->len] = 0;
+
+                    unsigned cnt = setMangleOverride(s, name);
+                    if (cnt > 1)
+                        error("can only apply to a single declaration");
+                }
+            }
+        }
+
+        if (sc2 != sc)
+            sc2->pop();
+    }
+    return;
+
+Lnodecl:
+    if (decl)
+    {
+        error("pragma is missing closing ';'");
+        goto Ldecl; // do them anyway, to avoid segfaults.
+    }
+}
+
+const char *PragmaDeclaration::kind() const
+{
+    return "pragma";
+}
+
+/********************************* ConditionalDeclaration ****************************/
+
+ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl)
+        : AttribDeclaration(decl)
+{
+    //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
+    this->condition = condition;
+    this->elsedecl = elsedecl;
+}
+
+Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    return new ConditionalDeclaration(condition->syntaxCopy(),
+        Dsymbol::arraySyntaxCopy(decl),
+        Dsymbol::arraySyntaxCopy(elsedecl));
+}
+
+bool ConditionalDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
+{
+    //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc);
+    if (condition->inc)
+    {
+        Dsymbols *d = condition->include(NULL, NULL) ? decl : elsedecl;
+        return Dsymbol::oneMembers(d, ps, ident);
+    }
+    else
+    {
+        bool res = (Dsymbol::oneMembers(    decl, ps, ident) && *ps == NULL &&
+                    Dsymbol::oneMembers(elsedecl, ps, ident) && *ps == NULL);
+        *ps = NULL;
+        return res;
+    }
+}
+
+// Decide if 'then' or 'else' code should be included
+
+Dsymbols *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sds)
+{
+    //printf("ConditionalDeclaration::include(sc = %p) _scope = %p\n", sc, _scope);
+    assert(condition);
+    return condition->include(_scope ? _scope : sc, sds) ? decl : elsedecl;
+}
+
+void ConditionalDeclaration::setScope(Scope *sc)
+{
+    Dsymbols *d = include(sc, NULL);
+
+    //printf("\tConditionalDeclaration::setScope '%s', d = %p\n",toChars(), d);
+    if (d)
+    {
+       for (size_t i = 0; i < d->dim; i++)
+       {
+           Dsymbol *s = (*d)[i];
+           s->setScope(sc);
+       }
+    }
+}
+
+void ConditionalDeclaration::addComment(const utf8_t *comment)
+{
+    /* Because addComment is called by the parser, if we called
+     * include() it would define a version before it was used.
+     * But it's no problem to drill down to both decl and elsedecl,
+     * so that's the workaround.
+     */
+
+    if (comment)
+    {
+        Dsymbols *d = decl;
+
+        for (int j = 0; j < 2; j++)
+        {
+            if (d)
+            {
+                for (size_t i = 0; i < d->dim; i++)
+                {
+                    Dsymbol *s = (*d)[i];
+                    //printf("ConditionalDeclaration::addComment %s\n", s->toChars());
+                    s->addComment(comment);
+                }
+            }
+            d = elsedecl;
+        }
+    }
+}
+
+/***************************** StaticIfDeclaration ****************************/
+
+StaticIfDeclaration::StaticIfDeclaration(Condition *condition,
+        Dsymbols *decl, Dsymbols *elsedecl)
+        : ConditionalDeclaration(condition, decl, elsedecl)
+{
+    //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
+    scopesym = NULL;
+    addisdone = false;
+}
+
+Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    return new StaticIfDeclaration(condition->syntaxCopy(),
+        Dsymbol::arraySyntaxCopy(decl),
+        Dsymbol::arraySyntaxCopy(elsedecl));
+}
+
+/****************************************
+ * Different from other AttribDeclaration subclasses, include() call requires
+ * the completion of addMember and setScope phases.
+ */
+Dsymbols *StaticIfDeclaration::include(Scope *sc, ScopeDsymbol *sds)
+{
+    //printf("StaticIfDeclaration::include(sc = %p) _scope = %p\n", sc, _scope);
+
+    if (condition->inc == 0)
+    {
+        assert(scopesym);   // addMember is already done
+        assert(_scope);      // setScope is already done
+
+        Dsymbols *d = ConditionalDeclaration::include(_scope, scopesym);
+
+        if (d && !addisdone)
+        {
+            // Add members lazily.
+            for (size_t i = 0; i < d->dim; i++)
+            {
+                Dsymbol *s = (*d)[i];
+                s->addMember(_scope, scopesym);
+            }
+
+            // Set the member scopes lazily.
+            for (size_t i = 0; i < d->dim; i++)
+            {
+                Dsymbol *s = (*d)[i];
+                s->setScope(_scope);
+            }
+
+            addisdone = true;
+        }
+        return d;
+    }
+    else
+    {
+        return ConditionalDeclaration::include(sc, scopesym);
+    }
+}
+
+void StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+    //printf("StaticIfDeclaration::addMember() '%s'\n", toChars());
+    /* This is deferred until the condition evaluated later (by the include() call),
+     * so that expressions in the condition can refer to declarations
+     * in the same scope, such as:
+     *
+     * template Foo(int i)
+     * {
+     *     const int j = i + 1;
+     *     static if (j == 3)
+     *         const int k;
+     * }
+     */
+    this->scopesym = sds;
+}
+
+void StaticIfDeclaration::importAll(Scope *sc)
+{
+    // do not evaluate condition before semantic pass
+}
+
+void StaticIfDeclaration::setScope(Scope *sc)
+{
+    // do not evaluate condition before semantic pass
+
+    // But do set the scope, in case we need it for forward referencing
+    Dsymbol::setScope(sc);
+}
+
+void StaticIfDeclaration::semantic(Scope *sc)
+{
+    AttribDeclaration::semantic(sc);
+}
+
+const char *StaticIfDeclaration::kind() const
+{
+    return "static if";
+}
+
+/***************************** CompileDeclaration *****************************/
+
+// These are mixin declarations, like mixin("int x");
+
+CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
+    : AttribDeclaration(NULL)
+{
+    //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
+    this->loc = loc;
+    this->exp = exp;
+    this->scopesym = NULL;
+    this->compiled = false;
+}
+
+Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
+    return new CompileDeclaration(loc, exp->syntaxCopy());
+}
+
+void CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+    //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
+    this->scopesym = sds;
+}
+
+void CompileDeclaration::setScope(Scope *sc)
+{
+    Dsymbol::setScope(sc);
+}
+
+void CompileDeclaration::compileIt(Scope *sc)
+{
+    //printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp->toChars());
+    sc = sc->startCTFE();
+    exp = ::semantic(exp, sc);
+    exp = resolveProperties(sc, exp);
+    sc = sc->endCTFE();
+
+    if (exp->op != TOKerror)
+    {
+        Expression *e = exp->ctfeInterpret();
+        StringExp *se = e->toStringExp();
+        if (!se)
+            exp->error("argument to mixin must be a string, not (%s) of type %s", exp->toChars(), exp->type->toChars());
+        else
+        {
+            se = se->toUTF8(sc);
+            unsigned errors = global.errors;
+            Parser p(loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+            p.nextToken();
+
+            decl = p.parseDeclDefs(0);
+            if (p.token.value != TOKeof)
+                exp->error("incomplete mixin declaration (%s)", se->toChars());
+            if (p.errors)
+            {
+                assert(global.errors != errors);
+                decl = NULL;
+            }
+        }
+    }
+}
+
+void CompileDeclaration::semantic(Scope *sc)
+{
+    //printf("CompileDeclaration::semantic()\n");
+
+    if (!compiled)
+    {
+        compileIt(sc);
+        AttribDeclaration::addMember(sc, scopesym);
+        compiled = true;
+
+        if (_scope && decl)
+        {
+            for (size_t i = 0; i < decl->dim; i++)
+            {
+                Dsymbol *s = (*decl)[i];
+                s->setScope(_scope);
+            }
+        }
+    }
+    AttribDeclaration::semantic(sc);
+}
+
+const char *CompileDeclaration::kind() const
+{
+    return "mixin";
+}
+
+/***************************** UserAttributeDeclaration *****************************/
+
+UserAttributeDeclaration::UserAttributeDeclaration(Expressions *atts, Dsymbols *decl)
+        : AttribDeclaration(decl)
+{
+    //printf("UserAttributeDeclaration()\n");
+    this->atts = atts;
+}
+
+Dsymbol *UserAttributeDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars());
+    assert(!s);
+    return new UserAttributeDeclaration(
+        Expression::arraySyntaxCopy(this->atts),
+        Dsymbol::arraySyntaxCopy(decl));
+}
+
+Scope *UserAttributeDeclaration::newScope(Scope *sc)
+{
+    Scope *sc2 = sc;
+    if (atts && atts->dim)
+    {
+        // create new one for changes
+        sc2 = sc->copy();
+        sc2->userAttribDecl = this;
+    }
+    return sc2;
+}
+
+void UserAttributeDeclaration::setScope(Scope *sc)
+{
+    //printf("UserAttributeDeclaration::setScope() %p\n", this);
+    if (decl)
+        Dsymbol::setScope(sc);  // for forward reference of UDAs
+
+    return AttribDeclaration::setScope(sc);
+}
+
+void UserAttributeDeclaration::semantic(Scope *sc)
+{
+    //printf("UserAttributeDeclaration::semantic() %p\n", this);
+    if (decl && !_scope)
+        Dsymbol::setScope(sc);  // for function local symbols
+
+    return AttribDeclaration::semantic(sc);
+}
+
+static void udaExpressionEval(Scope *sc, Expressions *exps)
+{
+    for (size_t i = 0; i < exps->dim; i++)
+    {
+        Expression *e = (*exps)[i];
+        if (e)
+        {
+            e = ::semantic(e, sc);
+            if (definitelyValueParameter(e))
+                e = e->ctfeInterpret();
+            if (e->op == TOKtuple)
+            {
+                TupleExp *te = (TupleExp *)e;
+                udaExpressionEval(sc, te->exps);
+            }
+            (*exps)[i] = e;
+        }
+    }
+}
+
+void UserAttributeDeclaration::semantic2(Scope *sc)
+{
+    if (decl && atts && atts->dim && _scope)
+    {
+        _scope = NULL;
+        udaExpressionEval(sc, atts);
+    }
+
+    AttribDeclaration::semantic2(sc);
+}
+
+Expressions *UserAttributeDeclaration::concat(Expressions *udas1, Expressions *udas2)
+{
+    Expressions *udas;
+    if (!udas1 || udas1->dim == 0)
+        udas = udas2;
+    else if (!udas2 || udas2->dim == 0)
+        udas = udas1;
+    else
+    {
+        /* Create a new tuple that combines them
+         * (do not append to left operand, as this is a copy-on-write operation)
+         */
+        udas = new Expressions();
+        udas->push(new TupleExp(Loc(), udas1));
+        udas->push(new TupleExp(Loc(), udas2));
+    }
+    return udas;
+}
+
+Expressions *UserAttributeDeclaration::getAttributes()
+{
+    if (Scope *sc = _scope)
+    {
+        _scope = NULL;
+        arrayExpressionSemantic(atts, sc);
+    }
+
+    Expressions *exps = new Expressions();
+    if (userAttribDecl)
+        exps->push(new TupleExp(Loc(), userAttribDecl->getAttributes()));
+    if (atts && atts->dim)
+        exps->push(new TupleExp(Loc(), atts));
+
+    return exps;
+}
+
+const char *UserAttributeDeclaration::kind() const
+{
+    return "UserAttribute";
+}
diff --git a/gcc/d/dfrontend/attrib.h b/gcc/d/dfrontend/attrib.h
new file mode 100644
index 00000000000..d37d45a53b9
--- /dev/null
+++ b/gcc/d/dfrontend/attrib.h
@@ -0,0 +1,278 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/attrib.h
+ */
+
+#ifndef DMD_ATTRIB_H
+#define DMD_ATTRIB_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+
+class Expression;
+class Statement;
+class LabelDsymbol;
+class Initializer;
+class Module;
+class Condition;
+
+/**************************************************************/
+
+class AttribDeclaration : public Dsymbol
+{
+public:
+    Dsymbols *decl;     // array of Dsymbol's
+
+    AttribDeclaration(Dsymbols *decl);
+    virtual Dsymbols *include(Scope *sc, ScopeDsymbol *sds);
+    int apply(Dsymbol_apply_ft_t fp, void *param);
+    static Scope *createNewScope(Scope *sc,
+        StorageClass newstc, LINK linkage, CPPMANGLE cppmangle, Prot protection,
+        int explicitProtection, AlignDeclaration *aligndecl, PINLINE inlining);
+    virtual Scope *newScope(Scope *sc);
+    void addMember(Scope *sc, ScopeDsymbol *sds);
+    void setScope(Scope *sc);
+    void importAll(Scope *sc);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    void addComment(const utf8_t *comment);
+    const char *kind() const;
+    bool oneMember(Dsymbol **ps, Identifier *ident);
+    void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+    bool hasPointers();
+    bool hasStaticCtorOrDtor();
+    void checkCtorConstInit();
+    void addLocalClass(ClassDeclarations *);
+    AttribDeclaration *isAttribDeclaration() { return this; }
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class StorageClassDeclaration : public AttribDeclaration
+{
+public:
+    StorageClass stc;
+
+    StorageClassDeclaration(StorageClass stc, Dsymbols *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Scope *newScope(Scope *sc);
+    bool oneMember(Dsymbol **ps, Identifier *ident);
+    StorageClassDeclaration *isStorageClassDeclaration() { return this; }
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DeprecatedDeclaration : public StorageClassDeclaration
+{
+public:
+    Expression *msg;
+    const char *msgstr;
+
+    DeprecatedDeclaration(Expression *msg, Dsymbols *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Scope *newScope(Scope *sc);
+    void setScope(Scope *sc);
+    void semantic2(Scope *sc);
+    const char *getMessage();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class LinkDeclaration : public AttribDeclaration
+{
+public:
+    LINK linkage;
+
+    LinkDeclaration(LINK p, Dsymbols *decl);
+    static LinkDeclaration *create(LINK p, Dsymbols *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Scope *newScope(Scope *sc);
+    const char *toChars();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class CPPMangleDeclaration : public AttribDeclaration
+{
+public:
+    CPPMANGLE cppmangle;
+
+    CPPMangleDeclaration(CPPMANGLE p, Dsymbols *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Scope *newScope(Scope *sc);
+    const char *toChars();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ProtDeclaration : public AttribDeclaration
+{
+public:
+    Prot protection;
+    Identifiers* pkg_identifiers;
+
+    ProtDeclaration(Loc loc, Prot p, Dsymbols *decl);
+    ProtDeclaration(Loc loc, Identifiers* pkg_identifiers, Dsymbols *decl);
+
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Scope *newScope(Scope *sc);
+    void addMember(Scope *sc, ScopeDsymbol *sds);
+    const char *kind() const;
+    const char *toPrettyChars(bool unused);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class AlignDeclaration : public AttribDeclaration
+{
+public:
+    Expression *ealign;
+    structalign_t salign;
+
+    AlignDeclaration(Loc loc, Expression *ealign, Dsymbols *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Scope *newScope(Scope *sc);
+    void setScope(Scope *sc);
+    void semantic2(Scope *sc);
+    structalign_t getAlignment();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class AnonDeclaration : public AttribDeclaration
+{
+public:
+    bool isunion;
+    int sem;                    // 1 if successful semantic()
+    unsigned anonoffset;        // offset of anonymous struct
+    unsigned anonstructsize;    // size of anonymous struct
+    unsigned anonalignsize;     // size of anonymous struct for alignment purposes
+
+    AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void setScope(Scope *sc);
+    void semantic(Scope *sc);
+    void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+    const char *kind() const;
+    AnonDeclaration *isAnonDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class PragmaDeclaration : public AttribDeclaration
+{
+public:
+    Expressions *args;          // array of Expression's
+
+    PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Scope *newScope(Scope *sc);
+    void semantic(Scope *sc);
+    const char *kind() const;
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ConditionalDeclaration : public AttribDeclaration
+{
+public:
+    Condition *condition;
+    Dsymbols *elsedecl; // array of Dsymbol's for else block
+
+    ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    bool oneMember(Dsymbol **ps, Identifier *ident);
+    Dsymbols *include(Scope *sc, ScopeDsymbol *sds);
+    void addComment(const utf8_t *comment);
+    void setScope(Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticIfDeclaration : public ConditionalDeclaration
+{
+public:
+    ScopeDsymbol *scopesym;
+    bool addisdone;
+
+    StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Dsymbols *include(Scope *sc, ScopeDsymbol *sds);
+    void addMember(Scope *sc, ScopeDsymbol *sds);
+    void setScope(Scope *sc);
+    void importAll(Scope *sc);
+    void semantic(Scope *sc);
+    const char *kind() const;
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticForeachDeclaration : public ConditionalDeclaration
+{
+public:
+    ScopeDsymbol *scopesym;
+    bool addisdone;
+
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Dsymbols *include(Scope *sc, ScopeDsymbol *sds);
+    void addMember(Scope *sc, ScopeDsymbol *sds);
+    void setScope(Scope *sc);
+    void importAll(Scope *sc);
+    void semantic(Scope *sc);
+    const char *kind() const;
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ForwardingAttribDeclaration: AttribDeclaration
+{
+public:
+        ForwardingScopeDsymbol *sym;
+
+        Scope* newScope(Scope *sc);
+        void addMember(Scope *sc, ScopeDsymbol *sds);
+        ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return this; }
+};
+
+// Mixin declarations
+
+class CompileDeclaration : public AttribDeclaration
+{
+public:
+    Expression *exp;
+
+    ScopeDsymbol *scopesym;
+    bool compiled;
+
+    CompileDeclaration(Loc loc, Expression *exp);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void addMember(Scope *sc, ScopeDsymbol *sds);
+    void setScope(Scope *sc);
+    void compileIt(Scope *sc);
+    void semantic(Scope *sc);
+    const char *kind() const;
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/**
+ * User defined attributes look like:
+ *      @(args, ...)
+ */
+class UserAttributeDeclaration : public AttribDeclaration
+{
+public:
+    Expressions *atts;
+
+    UserAttributeDeclaration(Expressions *atts, Dsymbols *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Scope *newScope(Scope *sc);
+    void setScope(Scope *sc);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    static Expressions *concat(Expressions *udas1, Expressions *udas2);
+    Expressions *getAttributes();
+    const char *kind() const;
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#endif /* DMD_ATTRIB_H */
diff --git a/gcc/d/dfrontend/blockexit.c b/gcc/d/dfrontend/blockexit.c
new file mode 100644
index 00000000000..5cc5dcb5829
--- /dev/null
+++ b/gcc/d/dfrontend/blockexit.c
@@ -0,0 +1,503 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2017 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+#include "statement.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+
+/* Only valid after semantic analysis
+ * If 'mustNotThrow' is true, generate an error if it throws
+ */
+int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow)
+{
+    class BlockExit : public Visitor
+    {
+    public:
+        FuncDeclaration *func;
+        bool mustNotThrow;
+        int result;
+
+        BlockExit(FuncDeclaration *func, bool mustNotThrow)
+            : func(func), mustNotThrow(mustNotThrow)
+        {
+            result = BEnone;
+        }
+
+        void visit(Statement *s)
+        {
+            printf("Statement::blockExit(%p)\n", s);
+            printf("%s\n", s->toChars());
+            assert(0);
+            result = BEany;
+        }
+
+        void visit(ErrorStatement *s)
+        {
+            result = BEany;
+        }
+
+        void visit(ExpStatement *s)
+        {
+            result = BEfallthru;
+            if (s->exp)
+            {
+                if (s->exp->op == TOKhalt)
+                {
+                    result = BEhalt;
+                    return;
+                }
+                if (s->exp->op == TOKassert)
+                {
+                    AssertExp *a = (AssertExp *)s->exp;
+                    if (a->e1->isBool(false))   // if it's an assert(0)
+                    {
+                        result = BEhalt;
+                        return;
+                    }
+                }
+                if (canThrow(s->exp, func, mustNotThrow))
+                    result |= BEthrow;
+            }
+        }
+
+        void visit(CompileStatement *s)
+        {
+            assert(global.errors);
+            result = BEfallthru;
+        }
+
+        void visit(CompoundStatement *cs)
+        {
+            //printf("CompoundStatement::blockExit(%p) %d result = x%X\n", cs, cs->statements->dim, result);
+            result = BEfallthru;
+            Statement *slast = NULL;
+            for (size_t i = 0; i < cs->statements->dim; i++)
+            {
+                Statement *s = (*cs->statements)[i];
+                if (s)
+                {
+                    //printf("result = x%x\n", result);
+                    //printf("s: %s\n", s->toChars());
+                    if (result & BEfallthru && slast)
+                    {
+                        slast = slast->last();
+                        if (slast && (slast->isCaseStatement() || slast->isDefaultStatement()) &&
+                                     (s->isCaseStatement() || s->isDefaultStatement()))
+                        {
+                            // Allow if last case/default was empty
+                            CaseStatement *sc = slast->isCaseStatement();
+                            DefaultStatement *sd = slast->isDefaultStatement();
+                            if (sc && (!sc->statement->hasCode() || sc->statement->isCaseStatement() || sc->statement->isErrorStatement()))
+                                ;
+                            else if (sd && (!sd->statement->hasCode() || sd->statement->isCaseStatement() || sd->statement->isErrorStatement()))
+                                ;
+                            else
+                            {
+                                const char *gototype = s->isCaseStatement() ? "case" : "default";
+                                s->deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
+                            }
+                        }
+                    }
+
+                    if (!(result & BEfallthru) && !s->comeFrom())
+                    {
+                        if (blockExit(s, func, mustNotThrow) != BEhalt && s->hasCode())
+                            s->warning("statement is not reachable");
+                    }
+                    else
+                    {
+                        result &= ~BEfallthru;
+                        result |= blockExit(s, func, mustNotThrow);
+                    }
+                    slast = s;
+                }
+            }
+        }
+
+        void visit(UnrolledLoopStatement *uls)
+        {
+            result = BEfallthru;
+            for (size_t i = 0; i < uls->statements->dim; i++)
+            {
+                Statement *s = (*uls->statements)[i];
+                if (s)
+                {
+                    int r = blockExit(s, func, mustNotThrow);
+                    result |= r & ~(BEbreak | BEcontinue | BEfallthru);
+                    if ((r & (BEfallthru | BEcontinue | BEbreak)) == 0)
+                        result &= ~BEfallthru;
+                }
+            }
+        }
+
+        void visit(ScopeStatement *s)
+        {
+            //printf("ScopeStatement::blockExit(%p)\n", s->statement);
+            result = s->statement ? blockExit(s->statement, func, mustNotThrow) : BEfallthru;
+        }
+
+        void visit(WhileStatement *s)
+        {
+            assert(global.errors);
+            result = BEfallthru;
+        }
+
+        void visit(DoStatement *s)
+        {
+            if (s->_body)
+            {
+                result = blockExit(s->_body, func, mustNotThrow);
+                if (result == BEbreak)
+                {
+                    result = BEfallthru;
+                    return;
+                }
+                if (result & BEcontinue)
+                    result |= BEfallthru;
+            }
+            else
+                result = BEfallthru;
+            if (result & BEfallthru)
+            {
+                if (canThrow(s->condition, func, mustNotThrow))
+                    result |= BEthrow;
+                if (!(result & BEbreak) && s->condition->isBool(true))
+                    result &= ~BEfallthru;
+            }
+            result &= ~(BEbreak | BEcontinue);
+        }
+
+        void visit(ForStatement *s)
+        {
+            result = BEfallthru;
+            if (s->_init)
+            {
+                result = blockExit(s->_init, func, mustNotThrow);
+                if (!(result & BEfallthru))
+                    return;
+            }
+            if (s->condition)
+            {
+                if (canThrow(s->condition, func, mustNotThrow))
+                    result |= BEthrow;
+                if (s->condition->isBool(true))
+                    result &= ~BEfallthru;
+                else if (s->condition->isBool(false))
+                    return;
+            }
+            else
+                result &= ~BEfallthru;  // the body must do the exiting
+            if (s->_body)
+            {
+                int r = blockExit(s->_body, func, mustNotThrow);
+                if (r & (BEbreak | BEgoto))
+                    result |= BEfallthru;
+                result |= r & ~(BEfallthru | BEbreak | BEcontinue);
+            }
+            if (s->increment && canThrow(s->increment, func, mustNotThrow))
+                result |= BEthrow;
+        }
+
+        void visit(ForeachStatement *s)
+        {
+            result = BEfallthru;
+            if (canThrow(s->aggr, func, mustNotThrow))
+                result |= BEthrow;
+            if (s->_body)
+                result |= blockExit(s->_body, func, mustNotThrow) & ~(BEbreak | BEcontinue);
+        }
+
+        void visit(ForeachRangeStatement *s)
+        {
+            assert(global.errors);
+            result = BEfallthru;
+        }
+
+        void visit(IfStatement *s)
+        {
+            //printf("IfStatement::blockExit(%p)\n", s);
+
+            result = BEnone;
+            if (canThrow(s->condition, func, mustNotThrow))
+                result |= BEthrow;
+            if (s->condition->isBool(true))
+            {
+                if (s->ifbody)
+                    result |= blockExit(s->ifbody, func, mustNotThrow);
+                else
+                    result |= BEfallthru;
+            }
+            else if (s->condition->isBool(false))
+            {
+                if (s->elsebody)
+                    result |= blockExit(s->elsebody, func, mustNotThrow);
+                else
+                    result |= BEfallthru;
+            }
+            else
+            {
+                if (s->ifbody)
+                    result |= blockExit(s->ifbody, func, mustNotThrow);
+                else
+                    result |= BEfallthru;
+                if (s->elsebody)
+                    result |= blockExit(s->elsebody, func, mustNotThrow);
+                else
+                    result |= BEfallthru;
+            }
+            //printf("IfStatement::blockExit(%p) = x%x\n", s, result);
+        }
+
+        void visit(ConditionalStatement *s)
+        {
+            result = blockExit(s->ifbody, func, mustNotThrow);
+            if (s->elsebody)
+                result |= blockExit(s->elsebody, func, mustNotThrow);
+        }
+
+        void visit(PragmaStatement *s)
+        {
+            result = BEfallthru;
+        }
+
+        void visit(StaticAssertStatement *s)
+        {
+            result = BEfallthru;
+        }
+
+        void visit(SwitchStatement *s)
+        {
+            result = BEnone;
+            if (canThrow(s->condition, func, mustNotThrow))
+                result |= BEthrow;
+            if (s->_body)
+            {
+                result |= blockExit(s->_body, func, mustNotThrow);
+                if (result & BEbreak)
+                {
+                    result |= BEfallthru;
+                    result &= ~BEbreak;
+                }
+            }
+            else
+                result |= BEfallthru;
+        }
+
+        void visit(CaseStatement *s)
+        {
+            result = blockExit(s->statement, func, mustNotThrow);
+        }
+
+        void visit(DefaultStatement *s)
+        {
+            result = blockExit(s->statement, func, mustNotThrow);
+        }
+
+        void visit(GotoDefaultStatement *s)
+        {
+            result = BEgoto;
+        }
+
+        void visit(GotoCaseStatement *s)
+        {
+            result = BEgoto;
+        }
+
+        void visit(SwitchErrorStatement *s)
+        {
+            // Switch errors are non-recoverable
+            result = BEhalt;
+        }
+
+        void visit(ReturnStatement *s)
+        {
+            result = BEreturn;
+            if (s->exp && canThrow(s->exp, func, mustNotThrow))
+                result |= BEthrow;
+        }
+
+        void visit(BreakStatement *s)
+        {
+            //printf("BreakStatement::blockExit(%p) = x%x\n", s, s->ident ? BEgoto : BEbreak);
+            result = s->ident ? BEgoto : BEbreak;
+        }
+
+        void visit(ContinueStatement *s)
+        {
+            result = s->ident ? BEgoto : BEcontinue;
+        }
+
+        void visit(SynchronizedStatement *s)
+        {
+            result = s->_body ? blockExit(s->_body, func, mustNotThrow) : BEfallthru;
+        }
+
+        void visit(WithStatement *s)
+        {
+            result = BEnone;
+            if (canThrow(s->exp, func, mustNotThrow))
+                result = BEthrow;
+            if (s->_body)
+                result |= blockExit(s->_body, func, mustNotThrow);
+            else
+                result |= BEfallthru;
+        }
+
+        void visit(TryCatchStatement *s)
+        {
+            assert(s->_body);
+            result = blockExit(s->_body, func, false);
+
+            int catchresult = 0;
+            for (size_t i = 0; i < s->catches->dim; i++)
+            {
+                Catch *c = (*s->catches)[i];
+                if (c->type == Type::terror)
+                    continue;
+
+                int cresult;
+                if (c->handler)
+                    cresult = blockExit(c->handler, func, mustNotThrow);
+                else
+                    cresult = BEfallthru;
+
+                /* If we're catching Object, then there is no throwing
+                 */
+                Identifier *id = c->type->toBasetype()->isClassHandle()->ident;
+                if (c->internalCatch && (cresult & BEfallthru))
+                {
+                    // Bugzilla 11542: leave blockExit flags of the body
+                    cresult &= ~BEfallthru;
+                }
+                else if (id == Id::Object || id == Id::Throwable)
+                {
+                    result &= ~(BEthrow | BEerrthrow);
+                }
+                else if (id == Id::Exception)
+                {
+                    result &= ~BEthrow;
+                }
+                catchresult |= cresult;
+            }
+            if (mustNotThrow && (result & BEthrow))
+            {
+                // now explain why this is nothrow
+                blockExit(s->_body, func, mustNotThrow);
+            }
+            result |= catchresult;
+        }
+
+        void visit(TryFinallyStatement *s)
+        {
+            result = BEfallthru;
+            if (s->_body)
+                result = blockExit(s->_body, func, false);
+
+            // check finally body as well, it may throw (bug #4082)
+            int finalresult = BEfallthru;
+            if (s->finalbody)
+                finalresult = blockExit(s->finalbody, func, false);
+
+            // If either body or finalbody halts
+            if (result == BEhalt)
+                finalresult = BEnone;
+            if (finalresult == BEhalt)
+                result = BEnone;
+
+            if (mustNotThrow)
+            {
+                // now explain why this is nothrow
+                if (s->_body && (result & BEthrow))
+                    blockExit(s->_body, func, mustNotThrow);
+                if (s->finalbody && (finalresult & BEthrow))
+                    blockExit(s->finalbody, func, mustNotThrow);
+            }
+
+        #if 0
+            // Bugzilla 13201: Mask to prevent spurious warnings for
+            // destructor call, exit of synchronized statement, etc.
+            if (result == BEhalt && finalresult != BEhalt && s->finalbody &&
+                s->finalbody->hasCode())
+            {
+                s->finalbody->warning("statement is not reachable");
+            }
+        #endif
+
+            if (!(finalresult & BEfallthru))
+                result &= ~BEfallthru;
+            result |= finalresult & ~BEfallthru;
+        }
+
+        void visit(OnScopeStatement *s)
+        {
+            // At this point, this statement is just an empty placeholder
+            result = BEfallthru;
+        }
+
+        void visit(ThrowStatement *s)
+        {
+            if (s->internalThrow)
+            {
+                // Bugzilla 8675: Allow throwing 'Throwable' object even if mustNotThrow.
+                result = BEfallthru;
+                return;
+            }
+
+            Type *t = s->exp->type->toBasetype();
+            ClassDeclaration *cd = t->isClassHandle();
+            assert(cd);
+
+            if (cd == ClassDeclaration::errorException ||
+                ClassDeclaration::errorException->isBaseOf(cd, NULL))
+            {
+                result = BEerrthrow;
+                return;
+            }
+            if (mustNotThrow)
+                s->error("%s is thrown but not caught", s->exp->type->toChars());
+
+            result = BEthrow;
+        }
+
+        void visit(GotoStatement *s)
+        {
+            //printf("GotoStatement::blockExit(%p)\n", s);
+            result = BEgoto;
+        }
+
+        void visit(LabelStatement *s)
+        {
+            //printf("LabelStatement::blockExit(%p)\n", s);
+            result = s->statement ? blockExit(s->statement, func, mustNotThrow) : BEfallthru;
+            if (s->breaks)
+                result |= BEfallthru;
+        }
+
+        void visit(CompoundAsmStatement *s)
+        {
+            if (mustNotThrow && !(s->stc & STCnothrow))
+                s->deprecation("asm statement is assumed to throw - mark it with 'nothrow' if it does not");
+
+            // Assume the worst
+            result = BEfallthru | BEreturn | BEgoto | BEhalt;
+            if (!(s->stc & STCnothrow)) result |= BEthrow;
+        }
+
+        void visit(ImportStatement *s)
+        {
+            result = BEfallthru;
+        }
+    };
+
+    BlockExit be(func, mustNotThrow);
+    s->accept(&be);
+    return be.result;
+}
diff --git a/gcc/d/dfrontend/boostlicense.txt b/gcc/d/dfrontend/boostlicense.txt
new file mode 100644
index 00000000000..36b7cd93cdf
--- /dev/null
+++ b/gcc/d/dfrontend/boostlicense.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/gcc/d/dfrontend/canthrow.c b/gcc/d/dfrontend/canthrow.c
new file mode 100644
index 00000000000..6ecfb61b479
--- /dev/null
+++ b/gcc/d/dfrontend/canthrow.c
@@ -0,0 +1,318 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/canthrow.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "init.h"
+#include "expression.h"
+#include "template.h"
+#include "statement.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "attrib.h"
+#include "tokens.h"
+
+bool Dsymbol_canThrow(Dsymbol *s, FuncDeclaration *func, bool mustNotThrow);
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+
+/********************************************
+ * Returns true if the expression may throw exceptions.
+ * If 'mustNotThrow' is true, generate an error if it throws
+ */
+
+bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow)
+{
+    //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars());
+
+    // stop walking if we determine this expression can throw
+    class CanThrow : public StoppableVisitor
+    {
+        FuncDeclaration *func;
+        bool mustNotThrow;
+
+    public:
+        CanThrow(FuncDeclaration *func, bool mustNotThrow)
+            : func(func), mustNotThrow(mustNotThrow)
+        {
+        }
+
+        void visit(Expression *)
+        {
+        }
+
+        void visit(DeclarationExp *de)
+        {
+            stop = Dsymbol_canThrow(de->declaration, func, mustNotThrow);
+        }
+
+        void visit(CallExp *ce)
+        {
+            if (global.errors && !ce->e1->type)
+                return;                       // error recovery
+
+            /* If calling a function or delegate that is typed as nothrow,
+             * then this expression cannot throw.
+             * Note that pure functions can throw.
+             */
+            Type *t = ce->e1->type->toBasetype();
+            if (ce->f && ce->f == func)
+                return;
+            if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow)
+                return;
+            if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow)
+                return;
+
+            if (mustNotThrow)
+            {
+                if (ce->f)
+                {
+                    ce->error("%s '%s' is not nothrow",
+                        ce->f->kind(), ce->f->toPrettyChars());
+                }
+                else
+                {
+                    Expression *e1 = ce->e1;
+                    if (e1->op == TOKstar)   // print 'fp' if e1 is (*fp)
+                        e1 = ((PtrExp *)e1)->e1;
+                    ce->error("'%s' is not nothrow", e1->toChars());
+                }
+            }
+            stop = true;
+        }
+
+        void visit(NewExp *ne)
+        {
+            if (ne->member)
+            {
+                if (ne->allocator)
+                {
+                    // Bugzilla 14407
+                    Type *t = ne->allocator->type->toBasetype();
+                    if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
+                    {
+                        if (mustNotThrow)
+                        {
+                            ne->error("%s '%s' is not nothrow",
+                                ne->allocator->kind(), ne->allocator->toPrettyChars());
+                        }
+                        stop = true;
+                    }
+                }
+                // See if constructor call can throw
+                Type *t = ne->member->type->toBasetype();
+                if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
+                {
+                    if (mustNotThrow)
+                    {
+                        ne->error("%s '%s' is not nothrow",
+                            ne->member->kind(), ne->member->toPrettyChars());
+                    }
+                    stop = true;
+                }
+            }
+            // regard storage allocation failures as not recoverable
+        }
+
+        void visit(DeleteExp *de)
+        {
+            Type *tb = de->e1->type->toBasetype();
+            AggregateDeclaration *ad = NULL;
+            switch (tb->ty)
+            {
+            case Tclass:
+                ad = ((TypeClass *)tb)->sym;
+                break;
+
+            case Tpointer:
+                tb = ((TypePointer *)tb)->next->toBasetype();
+                if (tb->ty == Tstruct)
+                    ad = ((TypeStruct *)tb)->sym;
+                break;
+
+            case Tarray:
+            {
+                Type *tv = tb->nextOf()->baseElemOf();
+                if (tv->ty == Tstruct)
+                {
+                    ad = ((TypeStruct *)tv)->sym;
+                    break;
+                }
+            }
+
+            default:
+                break;
+            }
+            if (!ad)
+                return;
+
+            if (ad->dtor)
+            {
+                Type *t = ad->dtor->type->toBasetype();
+                if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
+                {
+                    if (mustNotThrow)
+                    {
+                        de->error("%s '%s' is not nothrow",
+                            ad->dtor->kind(), ad->dtor->toPrettyChars());
+                    }
+                    stop = true;
+                }
+            }
+            if (ad->aggDelete && tb->ty != Tarray)
+            {
+                Type *t = ad->aggDelete->type;
+                if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
+                {
+                    if (mustNotThrow)
+                    {
+                        de->error("%s '%s' is not nothrow",
+                            ad->aggDelete->kind(), ad->aggDelete->toPrettyChars());
+                    }
+                    stop = true;
+                }
+            }
+        }
+
+        void visit(AssignExp *ae)
+        {
+            // blit-init cannot throw
+            if (ae->op == TOKblit)
+                return;
+
+            /* Element-wise assignment could invoke postblits.
+             */
+            Type *t;
+            if (ae->type->toBasetype()->ty == Tsarray)
+            {
+                if (!ae->e2->isLvalue())
+                    return;
+                t = ae->type;
+            }
+            else if (ae->e1->op == TOKslice)
+                t = ((SliceExp *)ae->e1)->e1->type;
+            else
+                return;
+
+            Type *tv = t->baseElemOf();
+            if (tv->ty != Tstruct)
+                return;
+            StructDeclaration *sd = ((TypeStruct *)tv)->sym;
+            if (!sd->postblit || sd->postblit->type->ty != Tfunction)
+                return;
+
+            if (((TypeFunction *)sd->postblit->type)->isnothrow)
+                ;
+            else
+            {
+                if (mustNotThrow)
+                {
+                    ae->error("%s '%s' is not nothrow",
+                        sd->postblit->kind(), sd->postblit->toPrettyChars());
+                }
+                stop = true;
+            }
+        }
+
+        void visit(NewAnonClassExp *)
+        {
+            assert(0);          // should have been lowered by semantic()
+        }
+    };
+
+    CanThrow ct(func, mustNotThrow);
+    return walkPostorder(e, &ct);
+}
+
+/**************************************
+ * Does symbol, when initialized, throw?
+ * Mirrors logic in Dsymbol_toElem().
+ */
+
+bool Dsymbol_canThrow(Dsymbol *s, FuncDeclaration *func, bool mustNotThrow)
+{
+    AttribDeclaration *ad;
+    VarDeclaration *vd;
+    TemplateMixin *tm;
+    TupleDeclaration *td;
+
+    //printf("Dsymbol_toElem() %s\n", s->toChars());
+    ad = s->isAttribDeclaration();
+    if (ad)
+    {
+        Dsymbols *decl = ad->include(NULL, NULL);
+        if (decl && decl->dim)
+        {
+            for (size_t i = 0; i < decl->dim; i++)
+            {
+                s = (*decl)[i];
+                if (Dsymbol_canThrow(s, func, mustNotThrow))
+                    return true;
+            }
+        }
+    }
+    else if ((vd = s->isVarDeclaration()) != NULL)
+    {
+        s = s->toAlias();
+        if (s != vd)
+            return Dsymbol_canThrow(s, func, mustNotThrow);
+        if (vd->storage_class & STCmanifest)
+            ;
+        else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared))
+            ;
+        else
+        {
+            if (vd->_init)
+            {
+                ExpInitializer *ie = vd->_init->isExpInitializer();
+                if (ie && canThrow(ie->exp, func, mustNotThrow))
+                    return true;
+            }
+            if (vd->needsScopeDtor())
+                return canThrow(vd->edtor, func, mustNotThrow);
+        }
+    }
+    else if ((tm = s->isTemplateMixin()) != NULL)
+    {
+        //printf("%s\n", tm->toChars());
+        if (tm->members)
+        {
+            for (size_t i = 0; i < tm->members->dim; i++)
+            {
+                Dsymbol *sm = (*tm->members)[i];
+                if (Dsymbol_canThrow(sm, func, mustNotThrow))
+                    return true;
+            }
+        }
+    }
+    else if ((td = s->isTupleDeclaration()) != NULL)
+    {
+        for (size_t i = 0; i < td->objects->dim; i++)
+        {
+            RootObject *o = (*td->objects)[i];
+            if (o->dyncast() == DYNCAST_EXPRESSION)
+            {
+                Expression *eo = (Expression *)o;
+                if (eo->op == TOKdsymbol)
+                {
+                    DsymbolExp *se = (DsymbolExp *)eo;
+                    if (Dsymbol_canThrow(se->s, func, mustNotThrow))
+                        return true;
+                }
+            }
+        }
+    }
+    return false;
+}
diff --git a/gcc/d/dfrontend/checkedint.c b/gcc/d/dfrontend/checkedint.c
new file mode 100644
index 00000000000..32d0c726daf
--- /dev/null
+++ b/gcc/d/dfrontend/checkedint.c
@@ -0,0 +1,564 @@
+
+/**********************************************
+ * This module implements integral arithmetic primitives that check
+ * for out-of-range results.
+ * This is a translation to C++ of D's core.checkedint
+ *
+ * Integral arithmetic operators operate on fixed width types.
+ * Results that are not representable in those fixed widths are silently
+ * truncated to fit.
+ * This module offers integral arithmetic primitives that produce the
+ * same results, but set an 'overflow' flag when such truncation occurs.
+ * The setting is sticky, meaning that numerous operations can be cascaded
+ * and then the flag need only be checked at the end.
+ * Whether the operation is signed or unsigned is indicated by an 's' or 'u'
+ * suffix, respectively. While this could be achieved without such suffixes by
+ * using overloading on the signedness of the types, the suffix makes it clear
+ * which is happening without needing to examine the types.
+ *
+ * While the generic versions of these functions are computationally expensive
+ * relative to the cost of the operation itself, compiler implementations are free
+ * to recognize them and generate equivalent and faster code.
+ *
+ * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks)
+ * Copyright: Copyright (c) Walter Bright 2014.
+ * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Authors:   Walter Bright
+ * Source:    https://github.com/D-Programming-Language/dmd/blob/master/src/root/port.c
+ */
+
+#include <assert.h>
+
+#include "checkedint.h"
+
+#ifdef __DMC__
+#undef UINT64_MAX
+#define UINT64_MAX      18446744073709551615ULL
+#undef UINT32_MAX
+#define UINT32_MAX      4294967295U
+#endif
+
+
+
+/*******************************
+ * Add two signed integers, checking for overflow.
+ *
+ * The overflow is sticky, meaning a sequence of operations can
+ * be done and overflow need only be checked at the end.
+ * Params:
+ *      x = left operand
+ *      y = right operand
+ *      overflow = set if an overflow occurs, is not affected otherwise
+ * Returns:
+ *      the sum
+ */
+
+int adds(int x, int y, bool& overflow)
+{
+    int64_t r = (int64_t)x + (int64_t)y;
+    if (r < INT32_MIN || r > INT32_MAX)
+        overflow = true;
+    return (int)r;
+}
+
+#ifdef DEBUG
+void unittest1()
+{
+    bool overflow = false;
+    assert(adds(2, 3, overflow) == 5);
+    assert(!overflow);
+    assert(adds(1, INT32_MAX - 1, overflow) == INT32_MAX);
+    assert(!overflow);
+    assert(adds(INT32_MIN + 1, -1, overflow) == INT32_MIN);
+    assert(!overflow);
+    assert(adds(INT32_MAX, 1, overflow) == INT32_MIN);
+    assert(overflow);
+    overflow = false;
+    assert(adds(INT32_MIN, -1, overflow) == INT32_MAX);
+    assert(overflow);
+    assert(adds(0, 0, overflow) == 0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+/// ditto
+int64_t adds(int64_t x, int64_t y, bool& overflow)
+{
+    int64_t r = (uint64_t)x + (uint64_t)y;
+    if (x <  0 && y <  0 && r >= 0 ||
+        x >= 0 && y >= 0 && r <  0)
+        overflow = true;
+    return r;
+}
+
+#ifdef DEBUG
+void unittest2()
+{
+    bool overflow = false;
+    assert(adds((int64_t)2, (int64_t)3, overflow) == 5);
+    assert(!overflow);
+    assert(adds((int64_t)1, INT64_MAX - 1, overflow) == INT64_MAX);
+    assert(!overflow);
+    assert(adds(INT64_MIN + 1, (int64_t)-1, overflow) == INT64_MIN);
+    assert(!overflow);
+    assert(adds(INT64_MAX, (int64_t)1, overflow) == INT64_MIN);
+    assert(overflow);
+    overflow = false;
+    assert(adds(INT64_MIN, (int64_t)-1, overflow) == INT64_MAX);
+    assert(overflow);
+    assert(adds((int64_t)0, (int64_t)0, overflow) == 0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+
+/*******************************
+ * Add two unsigned integers, checking for overflow (aka carry).
+ *
+ * The overflow is sticky, meaning a sequence of operations can
+ * be done and overflow need only be checked at the end.
+ * Params:
+ *      x = left operand
+ *      y = right operand
+ *      overflow = set if an overflow occurs, is not affected otherwise
+ * Returns:
+ *      the sum
+ */
+
+unsigned addu(unsigned x, unsigned y, bool& overflow)
+{
+    unsigned r = x + y;
+    if (r < x || r < y)
+        overflow = true;
+    return r;
+}
+
+#ifdef DEBUG
+void unittest3()
+{
+    bool overflow = false;
+    assert(addu(2U, 3U, overflow) == 5);
+    assert(!overflow);
+    assert(addu(1U, UINT32_MAX - 1U, overflow) == UINT32_MAX);
+    assert(!overflow);
+    assert(addu(0U, -1U, overflow) == UINT32_MAX);
+    assert(!overflow);
+    assert(addu(UINT32_MAX, 1U, overflow) == 0);
+    assert(overflow);
+    overflow = false;
+    assert(addu(0U + 1U, -1U, overflow) == 0);
+    assert(overflow);
+    assert(addu(0U, 0U, overflow) == 0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+/// ditto
+uint64_t addu(uint64_t x, uint64_t y, bool& overflow)
+{
+    uint64_t r = x + y;
+    if (r < x || r < y)
+        overflow = true;
+    return r;
+}
+
+#ifdef DEBUG
+void unittest4()
+{
+    bool overflow = false;
+    assert(addu((uint64_t)2, (uint64_t)3, overflow) == 5);
+    assert(!overflow);
+    assert(addu((uint64_t)1, UINT64_MAX - 1, overflow) == UINT64_MAX);
+    assert(!overflow);
+    assert(addu((uint64_t)0, (uint64_t)-1, overflow) == UINT64_MAX);
+    assert(!overflow);
+    assert(addu(UINT64_MAX, (uint64_t)1, overflow) == 0);
+    assert(overflow);
+    overflow = false;
+    assert(addu((uint64_t)0 + 1, (uint64_t)-1, overflow) == 0);
+    assert(overflow);
+    assert(addu((uint64_t)0, (uint64_t)0, overflow) == 0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+
+/*******************************
+ * Subtract two signed integers, checking for overflow.
+ *
+ * The overflow is sticky, meaning a sequence of operations can
+ * be done and overflow need only be checked at the end.
+ * Params:
+ *      x = left operand
+ *      y = right operand
+ *      overflow = set if an overflow occurs, is not affected otherwise
+ * Returns:
+ *      the sum
+ */
+
+int subs(int x, int y, bool& overflow)
+{
+    int64_t r = (int64_t)x - (int64_t)y;
+    if (r < INT32_MIN || r > INT32_MAX)
+        overflow = true;
+    return (int)r;
+}
+
+#ifdef DEBUG
+void unittest5()
+{
+    bool overflow = false;
+    assert(subs(2, -3, overflow) == 5);
+    assert(!overflow);
+    assert(subs(1, -INT32_MAX + 1, overflow) == INT32_MAX);
+    assert(!overflow);
+    assert(subs(INT32_MIN + 1, 1, overflow) == INT32_MIN);
+    assert(!overflow);
+    assert(subs(INT32_MAX, -1, overflow) == INT32_MIN);
+    assert(overflow);
+    overflow = false;
+    assert(subs(INT32_MIN, 1, overflow) == INT32_MAX);
+    assert(overflow);
+    assert(subs(0, 0, overflow) == 0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+/// ditto
+int64_t subs(int64_t x, int64_t y, bool& overflow)
+{
+    int64_t r = (uint64_t)x - (uint64_t)y;
+    if (x <  0 && y >= 0 && r >= 0 ||
+        x >= 0 && y <  0 && (r <  0 || y == INT64_MIN))
+        overflow = true;
+    return r;
+}
+
+#ifdef DEBUG
+void unittest6()
+{
+    bool overflow = false;
+    assert(subs((int64_t)2, (int64_t)-3, overflow) == 5);
+    assert(!overflow);
+    assert(subs((int64_t)1, -INT64_MAX + (int64_t)1, overflow) == INT64_MAX);
+    assert(!overflow);
+    assert(subs(INT64_MIN + 1, (int64_t)1, overflow) == INT64_MIN);
+    assert(!overflow);
+    assert(subs((int64_t)-1, INT64_MIN, overflow) == INT64_MAX);
+    assert(!overflow);
+    assert(subs(INT64_MAX, (int64_t)-1, overflow) == INT64_MIN);
+    assert(overflow);
+    overflow = false;
+    assert(subs(INT64_MIN, (int64_t)1, overflow) == INT64_MAX);
+    assert(overflow);
+    assert(subs((int64_t)0, (int64_t)0, overflow) == 0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+/*******************************
+ * Subtract two unsigned integers, checking for overflow (aka borrow).
+ *
+ * The overflow is sticky, meaning a sequence of operations can
+ * be done and overflow need only be checked at the end.
+ * Params:
+ *      x = left operand
+ *      y = right operand
+ *      overflow = set if an overflow occurs, is not affected otherwise
+ * Returns:
+ *      the sum
+ */
+
+unsigned subu(unsigned x, unsigned y, bool& overflow)
+{
+    if (x < y)
+        overflow = true;
+    return x - y;
+}
+
+#ifdef DEBUG
+void unittest7()
+{
+    bool overflow = false;
+    assert(subu(3U, 2U, overflow) == 1);
+    assert(!overflow);
+    assert(subu(UINT32_MAX, 1U, overflow) == UINT32_MAX - 1);
+    assert(!overflow);
+    assert(subu(1U, 1U, overflow) == 0);
+    assert(!overflow);
+    assert(subu(0U, 1U, overflow) == UINT32_MAX);
+    assert(overflow);
+    overflow = false;
+    assert(subu(UINT32_MAX - 1U, UINT32_MAX, overflow) == UINT32_MAX);
+    assert(overflow);
+    assert(subu(0U, 0U, overflow) == 0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+
+/// ditto
+uint64_t subu(uint64_t x, uint64_t y, bool& overflow)
+{
+    if (x < y)
+        overflow = true;
+    return x - y;
+}
+
+#ifdef DEBUG
+void unittest8()
+{
+    bool overflow = false;
+    assert(subu((uint64_t)3, (uint64_t)2, overflow) == 1);
+    assert(!overflow);
+    assert(subu(UINT64_MAX, (uint64_t)1, overflow) == UINT64_MAX - 1);
+    assert(!overflow);
+    assert(subu((uint64_t)1, (uint64_t)1, overflow) == 0);
+    assert(!overflow);
+    assert(subu((uint64_t)0, (uint64_t)1, overflow) == UINT64_MAX);
+    assert(overflow);
+    overflow = false;
+    assert(subu(UINT64_MAX - 1, UINT64_MAX, overflow) == UINT64_MAX);
+    assert(overflow);
+    assert(subu((uint64_t)0, (uint64_t)0, overflow) == 0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+
+/***********************************************
+ * Negate an integer.
+ *
+ * Params:
+ *      x = operand
+ *      overflow = set if x cannot be negated, is not affected otherwise
+ * Returns:
+ *      the negation of x
+ */
+
+int negs(int x, bool& overflow)
+{
+    if (x == (int)INT32_MIN)
+        overflow = true;
+    return -x;
+}
+
+#ifdef DEBUG
+void unittest9()
+{
+    bool overflow = false;
+    assert(negs(0, overflow) == -0);
+    assert(!overflow);
+    assert(negs(1234, overflow) == -1234);
+    assert(!overflow);
+    assert(negs(-5678, overflow) == 5678);
+    assert(!overflow);
+    assert(negs((int)INT32_MIN, overflow) == -INT32_MIN);
+    assert(overflow);
+    assert(negs(0, overflow) == -0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+/// ditto
+int64_t negs(int64_t x, bool& overflow)
+{
+    if (x == INT64_MIN)
+        overflow = true;
+    return -x;
+}
+
+#ifdef DEBUG
+void unittest10()
+{
+    bool overflow = false;
+    assert(negs((int64_t)0, overflow) == -0);
+    assert(!overflow);
+    assert(negs((int64_t)1234, overflow) == -1234);
+    assert(!overflow);
+    assert(negs((int64_t)-5678, overflow) == 5678);
+    assert(!overflow);
+    assert(negs(INT64_MIN, overflow) == -INT64_MIN);
+    assert(overflow);
+    assert(negs((int64_t)0, overflow) == -0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+
+/*******************************
+ * Multiply two signed integers, checking for overflow.
+ *
+ * The overflow is sticky, meaning a sequence of operations can
+ * be done and overflow need only be checked at the end.
+ * Params:
+ *      x = left operand
+ *      y = right operand
+ *      overflow = set if an overflow occurs, is not affected otherwise
+ * Returns:
+ *      the sum
+ */
+
+int muls(int x, int y, bool& overflow)
+{
+    int64_t r = (int64_t)x * (int64_t)y;
+    if (r < INT32_MIN || r > INT32_MAX)
+        overflow = true;
+    return (int)r;
+}
+
+#ifdef DEBUG
+void unittest11()
+{
+    bool overflow = false;
+    assert(muls(2, 3, overflow) == 6);
+    assert(!overflow);
+    assert(muls(-200, 300, overflow) == -60000);
+    assert(!overflow);
+    assert(muls(1, INT32_MAX, overflow) == INT32_MAX);
+    assert(!overflow);
+    assert(muls(INT32_MIN, 1, overflow) == INT32_MIN);
+    assert(!overflow);
+    assert(muls(INT32_MAX, 2, overflow) == (INT32_MAX * 2));
+    assert(overflow);
+    overflow = false;
+    assert(muls(INT32_MIN, -1, overflow) == INT32_MIN);
+    assert(overflow);
+    assert(muls(0, 0, overflow) == 0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+/// ditto
+int64_t muls(int64_t x, int64_t y, bool& overflow)
+{
+    int64_t r = (uint64_t)x * (uint64_t)y;
+    int64_t not0or1 = ~(int64_t)1;
+    if ((x & not0or1) && ((r == y) ? r : (r / x) != y))
+        overflow = true;
+    return r;
+}
+
+#ifdef DEBUG
+void unittest12()
+{
+    bool overflow = false;
+    assert(muls((int64_t)2, (int64_t)3, overflow) == 6);
+    assert(!overflow);
+    assert(muls((int64_t)-200, (int64_t)300, overflow) == -60000);
+    assert(!overflow);
+    assert(muls((int64_t)1, INT64_MAX, overflow) == INT64_MAX);
+    assert(!overflow);
+    assert(muls(INT64_MIN, (int64_t)1, overflow) == INT64_MIN);
+    assert(!overflow);
+    assert(muls(INT64_MAX, (int64_t)2, overflow) == (INT64_MAX * 2));
+    assert(overflow);
+    overflow = false;
+    assert(muls((int64_t)-1, INT64_MIN, overflow) == INT64_MIN);
+    assert(overflow);
+    overflow = false;
+    assert(muls(INT64_MIN, (int64_t)-1, overflow) == INT64_MIN);
+    assert(overflow);
+    assert(muls((int64_t)0, (int64_t)0, overflow) == 0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+
+/*******************************
+ * Multiply two unsigned integers, checking for overflow (aka carry).
+ *
+ * The overflow is sticky, meaning a sequence of operations can
+ * be done and overflow need only be checked at the end.
+ * Params:
+ *      x = left operand
+ *      y = right operand
+ *      overflow = set if an overflow occurs, is not affected otherwise
+ * Returns:
+ *      the sum
+ */
+
+unsigned mulu(unsigned x, unsigned y, bool& overflow)
+{
+    uint64_t r = (uint64_t)x * (uint64_t)y;
+    if (r > UINT32_MAX)
+        overflow = true;
+    return (unsigned)r;
+}
+
+#ifdef DEBUG
+void unittest13()
+{
+    bool overflow = false;
+    assert(mulu(2U, 3U, overflow) == 6);
+    assert(!overflow);
+    assert(mulu(1U, UINT32_MAX, overflow) == UINT32_MAX);
+    assert(!overflow);
+    assert(mulu(0U, 1U, overflow) == 0);
+    assert(!overflow);
+    assert(mulu(UINT32_MAX, 2U, overflow) == (unsigned)(UINT32_MAX * 2));
+    assert(overflow);
+    overflow = false;
+    assert(mulu(0U, -1U, overflow) == 0);
+    assert(!overflow);
+    overflow = true;
+    assert(mulu(0U, 0U, overflow) == 0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+/// ditto
+uint64_t mulu(uint64_t x, uint64_t y, bool& overflow)
+{
+    uint64_t r = x * y;
+    if (x && (r / x) != y)
+        overflow = true;
+    return r;
+}
+
+#ifdef DEBUG
+void unittest14()
+{
+    bool overflow = false;
+    assert(mulu((uint64_t)2, (uint64_t)3, overflow) == 6);
+    assert(!overflow);
+    assert(mulu(1, UINT64_MAX, overflow) == UINT64_MAX);
+    assert(!overflow);
+    assert(mulu((uint64_t)0, 1, overflow) == 0);
+    assert(!overflow);
+    assert(mulu(UINT64_MAX, 2, overflow) == (UINT64_MAX * 2));
+    assert(overflow);
+    overflow = false;
+    assert(mulu((uint64_t)0, -1, overflow) == 0);
+    assert(!overflow);
+    overflow = true;
+    assert(mulu((uint64_t)0, (uint64_t)0, overflow) == 0);
+    assert(overflow);                   // sticky
+}
+#endif
+
+#ifdef DEBUG
+struct CheckedintUnittest
+{
+    CheckedintUnittest()
+    {
+        unittest1();
+        unittest2();
+        unittest3();
+        unittest4();
+        unittest5();
+        unittest6();
+        unittest7();
+        unittest8();
+        unittest9();
+        unittest10();
+        unittest11();
+        unittest12();
+        unittest13();
+    }
+};
+
+static CheckedintUnittest unittest;
+#endif
+
+//void main() { }
diff --git a/gcc/d/dfrontend/checkedint.h b/gcc/d/dfrontend/checkedint.h
new file mode 100644
index 00000000000..17ee3418eed
--- /dev/null
+++ b/gcc/d/dfrontend/checkedint.h
@@ -0,0 +1,24 @@
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+#include <stdint.h>
+
+
+int adds(int x, int y, bool& overflow);
+int64_t adds(int64_t x, int64_t y, bool& overflow);
+unsigned addu(unsigned x, unsigned y, bool& overflow);
+uint64_t addu(uint64_t x, uint64_t y, bool& overflow);
+
+int subs(int x, int y, bool& overflow);
+int64_t subs(int64_t x, int64_t y, bool& overflow);
+unsigned subu(unsigned x, unsigned y, bool& overflow);
+uint64_t subu(uint64_t x, uint64_t y, bool& overflow);
+
+int negs(int x, bool& overflow);
+int64_t negs(int64_t x, bool& overflow);
+
+int muls(int x, int y, bool& overflow);
+int64_t muls(int64_t x, int64_t y, bool& overflow);
+unsigned mulu(unsigned x, unsigned y, bool& overflow);
+uint64_t mulu(uint64_t x, uint64_t y, bool& overflow);
diff --git a/gcc/d/dfrontend/clone.c b/gcc/d/dfrontend/clone.c
new file mode 100644
index 00000000000..2b4f4da325f
--- /dev/null
+++ b/gcc/d/dfrontend/clone.c
@@ -0,0 +1,1235 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/clone.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <new>
+
+#include "root.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "module.h"
+#include "id.h"
+#include "expression.h"
+#include "statement.h"
+#include "init.h"
+#include "template.h"
+#include "tokens.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+
+/*******************************************
+ * Merge function attributes pure, nothrow, @safe, @nogc, and @disable
+ */
+StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f)
+{
+    if (!f)
+        return s1;
+
+    StorageClass s2 = (f->storage_class & STCdisable);
+    TypeFunction *tf = (TypeFunction *)f->type;
+    if (tf->trust == TRUSTsafe)
+        s2 |= STCsafe;
+    else if (tf->trust == TRUSTsystem)
+        s2 |= STCsystem;
+    else if (tf->trust == TRUSTtrusted)
+        s2 |= STCtrusted;
+    if (tf->purity != PUREimpure)
+        s2 |= STCpure;
+    if (tf->isnothrow)
+        s2 |= STCnothrow;
+    if (tf->isnogc)
+        s2 |= STCnogc;
+
+    StorageClass stc = 0;
+    StorageClass sa = s1 & s2;
+    StorageClass so = s1 | s2;
+
+    if (so & STCsystem)
+        stc |= STCsystem;
+    else if (sa & STCtrusted)
+        stc |= STCtrusted;
+    else if ((so & (STCtrusted | STCsafe)) == (STCtrusted | STCsafe))
+        stc |= STCtrusted;
+    else if (sa & STCsafe)
+        stc |= STCsafe;
+
+    if (sa & STCpure)
+        stc |= STCpure;
+
+    if (sa & STCnothrow)
+        stc |= STCnothrow;
+
+    if (sa & STCnogc)
+        stc |= STCnogc;
+
+    if (so & STCdisable)
+        stc |= STCdisable;
+
+    return stc;
+}
+
+/*******************************************
+ * Check given aggregate actually has an identity opAssign or not.
+ * Params:
+ *      ad = struct or class
+ *      sc = current scope
+ * Returns:
+ *      if found, returns FuncDeclaration of opAssign, otherwise null
+ */
+FuncDeclaration *hasIdentityOpAssign(AggregateDeclaration *ad, Scope *sc)
+{
+    Dsymbol *assign = search_function(ad, Id::assign);
+    if (assign)
+    {
+        /* check identity opAssign exists
+         */
+        UnionExp er; new(&er) NullExp(ad->loc, ad->type);    // dummy rvalue
+        UnionExp el; new(&el) IdentifierExp(ad->loc, Id::p); // dummy lvalue
+        el.exp()->type = ad->type;
+        Expressions a;
+        a.setDim(1);
+
+        unsigned errors = global.startGagging();    // Do not report errors, even if the template opAssign fbody makes it.
+        sc = sc->push();
+        sc->tinst = NULL;
+        sc->minst = NULL;
+
+        a[0] = er.exp();
+        FuncDeclaration *f = resolveFuncCall(ad->loc, sc, assign, NULL, ad->type, &a, 1);
+        if (!f)
+        {
+            a[0] = el.exp();
+            f = resolveFuncCall(ad->loc, sc, assign, NULL, ad->type, &a, 1);
+        }
+
+        sc = sc->pop();
+        global.endGagging(errors);
+
+        if (f)
+        {
+            if (f->errors)
+                return NULL;
+            int varargs;
+            Parameters *fparams = f->getParameters(&varargs);
+            if (fparams->dim >= 1)
+            {
+                Parameter *fparam0 = Parameter::getNth(fparams, 0);
+                if (fparam0->type->toDsymbol(NULL) != ad)
+                    f = NULL;
+            }
+        }
+        // BUGS: This detection mechanism cannot find some opAssign-s like follows:
+        // struct S { void opAssign(ref immutable S) const; }
+        return f;
+    }
+    return NULL;
+}
+
+/*******************************************
+ * We need an opAssign for the struct if
+ * it has a destructor or a postblit.
+ * We need to generate one if a user-specified one does not exist.
+ */
+bool needOpAssign(StructDeclaration *sd)
+{
+    //printf("StructDeclaration::needOpAssign() %s\n", sd->toChars());
+    if (sd->isUnionDeclaration())
+        return false;
+
+    if (sd->hasIdentityAssign)
+        goto Lneed;         // because has identity==elaborate opAssign
+
+    if (sd->dtor || sd->postblit)
+        goto Lneed;
+
+    /* If any of the fields need an opAssign, then we
+     * need it too.
+     */
+    for (size_t i = 0; i < sd->fields.dim; i++)
+    {
+        VarDeclaration *v = sd->fields[i];
+        if (v->storage_class & STCref)
+            continue;
+        if (v->overlapped)              // if field of a union
+            continue;                   // user must handle it themselves
+        Type *tv = v->type->baseElemOf();
+        if (tv->ty == Tstruct)
+        {
+            TypeStruct *ts = (TypeStruct *)tv;
+            if (ts->sym->isUnionDeclaration())
+                continue;
+            if (needOpAssign(ts->sym))
+                goto Lneed;
+        }
+    }
+    //printf("\tdontneed\n");
+    return false;
+
+Lneed:
+    //printf("\tneed\n");
+    return true;
+}
+
+/******************************************
+ * Build opAssign for struct.
+ *      ref S opAssign(S s) { ... }
+ *
+ * Note that s will be constructed onto the stack, and probably
+ * copy-constructed in caller site.
+ *
+ * If S has copy copy construction and/or destructor,
+ * the body will make bit-wise object swap:
+ *          S __swap = this; // bit copy
+ *          this = s;        // bit copy
+ *          __swap.dtor();
+ * Instead of running the destructor on s, run it on tmp instead.
+ *
+ * Otherwise, the body will make member-wise assignments:
+ * Then, the body is:
+ *          this.field1 = s.field1;
+ *          this.field2 = s.field2;
+ *          ...;
+ */
+FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc)
+{
+    if (FuncDeclaration *f = hasIdentityOpAssign(sd, sc))
+    {
+        sd->hasIdentityAssign = true;
+        return f;
+    }
+    // Even if non-identity opAssign is defined, built-in identity opAssign
+    // will be defined.
+
+    if (!needOpAssign(sd))
+        return NULL;
+
+    //printf("StructDeclaration::buildOpAssign() %s\n", sd->toChars());
+    StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
+    Loc declLoc = sd->loc;
+    Loc loc = Loc();    // internal code should have no loc to prevent coverage
+
+    // One of our sub-field might have `@disable opAssign` so we need to
+    // check for it.
+    // In this event, it will be reflected by having `stc` (opAssign's
+    // storage class) include `STCdisabled`.
+    for (size_t i = 0; i < sd->fields.dim; i++)
+    {
+        VarDeclaration *v = sd->fields[i];
+        if (v->storage_class & STCref)
+            continue;
+        if (v->overlapped)
+            continue;
+        Type *tv = v->type->baseElemOf();
+        if (tv->ty != Tstruct)
+            continue;
+
+        StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
+        stc = mergeFuncAttrs(stc, hasIdentityOpAssign(sdv, sc));
+    }
+
+    if (sd->dtor || sd->postblit)
+    {
+        if (!sd->type->isAssignable())  // Bugzilla 13044
+            return NULL;
+        stc = mergeFuncAttrs(stc, sd->dtor);
+        if (stc & STCsafe)
+            stc = (stc & ~STCsafe) | STCtrusted;
+    }
+
+    Parameters *fparams = new Parameters;
+    fparams->push(new Parameter(STCnodtor, sd->type, Id::p, NULL));
+    TypeFunction *tf = new TypeFunction(fparams, sd->handleType(), 0, LINKd, stc | STCref);
+
+    FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf);
+    fop->storage_class |= STCinference;
+    fop->generated = true;
+    Expression *e = NULL;
+    if (stc & STCdisable)
+    {
+    }
+    else if (sd->dtor || sd->postblit)
+    {
+        /* Do swap this and rhs.
+         *    __swap = this; this = s; __swap.dtor();
+         */
+        //printf("\tswap copy\n");
+        Identifier *idtmp = Identifier::generateId("__swap");
+        VarDeclaration *tmp = NULL;
+        AssignExp *ec = NULL;
+        if (sd->dtor)
+        {
+            tmp = new VarDeclaration(loc, sd->type, idtmp, new VoidInitializer(loc));
+            tmp->storage_class |= STCnodtor | STCtemp | STCctfe;
+            e = new DeclarationExp(loc, tmp);
+            ec = new BlitExp(loc, new VarExp(loc, tmp), new ThisExp(loc));
+            e = Expression::combine(e, ec);
+        }
+        ec = new BlitExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id::p));
+        e = Expression::combine(e, ec);
+        if (sd->dtor)
+        {
+            /* Instead of running the destructor on s, run it
+             * on tmp. This avoids needing to copy tmp back in to s.
+             */
+            Expression *ec2 = new DotVarExp(loc, new VarExp(loc, tmp), sd->dtor, false);
+            ec2 = new CallExp(loc, ec2);
+            e = Expression::combine(e, ec2);
+        }
+    }
+    else
+    {
+        /* Do memberwise copy.
+         *
+         * If sd is a nested struct, its vthis field assignment is:
+         * 1. If it's nested in a class, it's a rebind of class reference.
+         * 2. If it's nested in a function or struct, it's an update of void*.
+         * In both cases, it will change the parent context.
+         */
+        //printf("\tmemberwise copy\n");
+        for (size_t i = 0; i < sd->fields.dim; i++)
+        {
+            VarDeclaration *v = sd->fields[i];
+            // this.v = s.v;
+            AssignExp *ec = new AssignExp(loc,
+                new DotVarExp(loc, new ThisExp(loc), v),
+                new DotVarExp(loc, new IdentifierExp(loc, Id::p), v));
+            e = Expression::combine(e, ec);
+        }
+    }
+    if (e)
+    {
+        Statement *s1 = new ExpStatement(loc, e);
+
+        /* Add:
+         *   return this;
+         */
+        e = new ThisExp(loc);
+        Statement *s2 = new ReturnStatement(loc, e);
+
+        fop->fbody = new CompoundStatement(loc, s1, s2);
+        tf->isreturn = true;
+    }
+
+    sd->members->push(fop);
+    fop->addMember(sc, sd);
+    sd->hasIdentityAssign = true;        // temporary mark identity assignable
+
+    unsigned errors = global.startGagging();    // Do not report errors, even if the template opAssign fbody makes it.
+    Scope *sc2 = sc->push();
+    sc2->stc = 0;
+    sc2->linkage = LINKd;
+
+    fop->semantic(sc2);
+    fop->semantic2(sc2);
+    // Bugzilla 15044: fop->semantic3 isn't run here for lazy forward reference resolution.
+
+    sc2->pop();
+    if (global.endGagging(errors))    // if errors happened
+    {
+        // Disable generated opAssign, because some members forbid identity assignment.
+        fop->storage_class |= STCdisable;
+        fop->fbody = NULL;  // remove fbody which contains the error
+    }
+
+    //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd->toChars(), (fop->storage_class & STCdisable) != 0);
+
+    return fop;
+}
+
+/*******************************************
+ * We need an opEquals for the struct if
+ * any fields has an opEquals.
+ * Generate one if a user-specified one does not exist.
+ */
+bool needOpEquals(StructDeclaration *sd)
+{
+    //printf("StructDeclaration::needOpEquals() %s\n", sd->toChars());
+    if (sd->isUnionDeclaration())
+        goto Ldontneed;
+
+    if (sd->hasIdentityEquals)
+        goto Lneed;
+
+    /* If any of the fields has an opEquals, then we
+     * need it too.
+     */
+    for (size_t i = 0; i < sd->fields.dim; i++)
+    {
+        VarDeclaration *v = sd->fields[i];
+        if (v->storage_class & STCref)
+            continue;
+        if (v->overlapped)
+            continue;
+        Type *tv = v->type->toBasetype();
+        Type *tvbase = tv->baseElemOf();
+        if (tvbase->ty == Tstruct)
+        {
+            TypeStruct *ts = (TypeStruct *)tvbase;
+            if (ts->sym->isUnionDeclaration())
+                continue;
+            if (needOpEquals(ts->sym))
+                goto Lneed;
+            if (ts->sym->aliasthis)     // Bugzilla 14806
+                goto Lneed;
+        }
+        if (tv->isfloating())
+        {
+            // This is necessray for:
+            //  1. comparison of +0.0 and -0.0 should be true.
+            //  2. comparison of NANs should be false always.
+            goto Lneed;
+        }
+        if (tv->ty == Tarray)
+            goto Lneed;
+        if (tv->ty == Taarray)
+            goto Lneed;
+        if (tv->ty == Tclass)
+            goto Lneed;
+    }
+Ldontneed:
+    //printf("\tdontneed\n");
+    return false;
+
+Lneed:
+    //printf("\tneed\n");
+    return true;
+}
+
+/*******************************************
+ * Check given aggregate actually has an identity opEquals or not.
+ */
+FuncDeclaration *hasIdentityOpEquals(AggregateDeclaration *ad,  Scope *sc)
+{
+    Dsymbol *eq = search_function(ad, Id::eq);
+    if (eq)
+    {
+        /* check identity opEquals exists
+         */
+        UnionExp er; new(&er) NullExp(ad->loc, NULL);        // dummy rvalue
+        UnionExp el; new(&el) IdentifierExp(ad->loc, Id::p); // dummy lvalue
+        Expressions a;
+        a.setDim(1);
+        for (size_t i = 0; i < 5; i++)
+        {
+            Type *tthis = NULL;         // dead-store to prevent spurious warning
+            switch (i)
+            {
+                case 0:  tthis = ad->type;                  break;
+                case 1:  tthis = ad->type->constOf();       break;
+                case 2:  tthis = ad->type->immutableOf();   break;
+                case 3:  tthis = ad->type->sharedOf();      break;
+                case 4:  tthis = ad->type->sharedConstOf(); break;
+                default: assert(0);
+            }
+            FuncDeclaration *f = NULL;
+
+            unsigned errors = global.startGagging();    // Do not report errors, even if the template opAssign fbody makes it.
+            sc = sc->push();
+            sc->tinst = NULL;
+            sc->minst = NULL;
+
+            for (size_t j = 0; j < 2; j++)
+            {
+                a[0] = (j == 0 ? er.exp() : el.exp());
+                a[0]->type = tthis;
+                f = resolveFuncCall(ad->loc, sc, eq, NULL, tthis, &a, 1);
+                if (f)
+                    break;
+            }
+
+            sc = sc->pop();
+            global.endGagging(errors);
+
+            if (f)
+            {
+                if (f->errors)
+                    return NULL;
+                return f;
+            }
+        }
+    }
+    return NULL;
+}
+
+/******************************************
+ * Build opEquals for struct.
+ *      const bool opEquals(const S s) { ... }
+ *
+ * By fixing bugzilla 3789, opEquals is changed to be never implicitly generated.
+ * Now, struct objects comparison s1 == s2 is translated to:
+ *      s1.tupleof == s2.tupleof
+ * to calculate structural equality. See EqualExp::op_overload.
+ */
+FuncDeclaration *buildOpEquals(StructDeclaration *sd, Scope *sc)
+{
+    if (hasIdentityOpEquals(sd, sc))
+    {
+        sd->hasIdentityEquals = true;
+    }
+    return NULL;
+}
+
+/******************************************
+ * Build __xopEquals for TypeInfo_Struct
+ *      static bool __xopEquals(ref const S p, ref const S q)
+ *      {
+ *          return p == q;
+ *      }
+ *
+ * This is called by TypeInfo.equals(p1, p2). If the struct does not support
+ * const objects comparison, it will throw "not implemented" Error in runtime.
+ */
+FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc)
+{
+    if (!needOpEquals(sd))
+        return NULL;        // bitwise comparison would work
+
+    //printf("StructDeclaration::buildXopEquals() %s\n", sd->toChars());
+    if (Dsymbol *eq = search_function(sd, Id::eq))
+    {
+        if (FuncDeclaration *fd = eq->isFuncDeclaration())
+        {
+            TypeFunction *tfeqptr;
+            {
+                Scope scx;
+
+                /* const bool opEquals(ref const S s);
+                 */
+                Parameters *parameters = new Parameters;
+                parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL));
+                tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd);
+                tfeqptr->mod = MODconst;
+                tfeqptr = (TypeFunction *)tfeqptr->semantic(Loc(), &scx);
+            }
+            fd = fd->overloadExactMatch(tfeqptr);
+            if (fd)
+                return fd;
+        }
+    }
+
+    if (!sd->xerreq)
+    {
+        // object._xopEquals
+        Identifier *id = Identifier::idPool("_xopEquals");
+        Expression *e = new IdentifierExp(sd->loc, Id::empty);
+        e = new DotIdExp(sd->loc, e, Id::object);
+        e = new DotIdExp(sd->loc, e, id);
+        e = semantic(e, sc);
+        Dsymbol *s = getDsymbol(e);
+        assert(s);
+        sd->xerreq = s->isFuncDeclaration();
+    }
+
+    Loc declLoc = Loc();    // loc is unnecessary so __xopEquals is never called directly
+    Loc loc = Loc();        // loc is unnecessary so errors are gagged
+
+    Parameters *parameters = new Parameters;
+    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
+    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL));
+    TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
+
+    Identifier *id = Id::xopEquals;
+    FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);
+    fop->generated = true;
+    Expression *e1 = new IdentifierExp(loc, Id::p);
+    Expression *e2 = new IdentifierExp(loc, Id::q);
+    Expression *e = new EqualExp(TOKequal, loc, e1, e2);
+
+    fop->fbody = new ReturnStatement(loc, e);
+
+    unsigned errors = global.startGagging();    // Do not report errors
+    Scope *sc2 = sc->push();
+    sc2->stc = 0;
+    sc2->linkage = LINKd;
+
+    fop->semantic(sc2);
+    fop->semantic2(sc2);
+
+    sc2->pop();
+    if (global.endGagging(errors))    // if errors happened
+        fop = sd->xerreq;
+
+    return fop;
+}
+
+/******************************************
+ * Build __xopCmp for TypeInfo_Struct
+ *      static bool __xopCmp(ref const S p, ref const S q)
+ *      {
+ *          return p.opCmp(q);
+ *      }
+ *
+ * This is called by TypeInfo.compare(p1, p2). If the struct does not support
+ * const objects comparison, it will throw "not implemented" Error in runtime.
+ */
+FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc)
+{
+    //printf("StructDeclaration::buildXopCmp() %s\n", toChars());
+    if (Dsymbol *cmp = search_function(sd, Id::cmp))
+    {
+        if (FuncDeclaration *fd = cmp->isFuncDeclaration())
+        {
+            TypeFunction *tfcmpptr;
+            {
+                Scope scx;
+
+                /* const int opCmp(ref const S s);
+                 */
+                Parameters *parameters = new Parameters;
+                parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL));
+                tfcmpptr = new TypeFunction(parameters, Type::tint32, 0, LINKd);
+                tfcmpptr->mod = MODconst;
+                tfcmpptr = (TypeFunction *)tfcmpptr->semantic(Loc(), &scx);
+            }
+            fd = fd->overloadExactMatch(tfcmpptr);
+            if (fd)
+                return fd;
+        }
+    }
+    else
+    {
+#if 0   // FIXME: doesn't work for recursive alias this
+        /* Check opCmp member exists.
+         * Consider 'alias this', but except opDispatch.
+         */
+        Expression *e = new DsymbolExp(sd->loc, sd);
+        e = new DotIdExp(sd->loc, e, Id::cmp);
+        Scope *sc2 = sc->push();
+        e = e->trySemantic(sc2);
+        sc2->pop();
+        if (e)
+        {
+            Dsymbol *s = NULL;
+            switch (e->op)
+            {
+                case TOKoverloadset:    s = ((OverExp *)e)->vars;       break;
+                case TOKscope:          s = ((ScopeExp *)e)->sds;       break;
+                case TOKvar:            s = ((VarExp *)e)->var;         break;
+                default:                break;
+            }
+            if (!s || s->ident != Id::cmp)
+                e = NULL;   // there's no valid member 'opCmp'
+        }
+        if (!e)
+            return NULL;    // bitwise comparison would work
+        /* Essentially, a struct which does not define opCmp is not comparable.
+         * At this time, typeid(S).compare might be correct that throwing "not implement" Error.
+         * But implementing it would break existing code, such as:
+         *
+         * struct S { int value; }  // no opCmp
+         * int[S] aa;   // Currently AA key uses bitwise comparison
+         *              // (It's default behavior of TypeInfo_Strust.compare).
+         *
+         * Not sure we should fix this inconsistency, so just keep current behavior.
+         */
+#else
+        return NULL;
+#endif
+    }
+
+    if (!sd->xerrcmp)
+    {
+        // object._xopCmp
+        Identifier *id = Identifier::idPool("_xopCmp");
+        Expression *e = new IdentifierExp(sd->loc, Id::empty);
+        e = new DotIdExp(sd->loc, e, Id::object);
+        e = new DotIdExp(sd->loc, e, id);
+        e = semantic(e, sc);
+        Dsymbol *s = getDsymbol(e);
+        assert(s);
+        sd->xerrcmp = s->isFuncDeclaration();
+    }
+
+    Loc declLoc = Loc();    // loc is unnecessary so __xopCmp is never called directly
+    Loc loc = Loc();        // loc is unnecessary so errors are gagged
+
+    Parameters *parameters = new Parameters;
+    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
+    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL));
+    TypeFunction *tf = new TypeFunction(parameters, Type::tint32, 0, LINKd);
+
+    Identifier *id = Id::xopCmp;
+    FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);
+    fop->generated = true;
+    Expression *e1 = new IdentifierExp(loc, Id::p);
+    Expression *e2 = new IdentifierExp(loc, Id::q);
+#ifdef IN_GCC
+    Expression *e = new CallExp(loc, new DotIdExp(loc, e1, Id::cmp), e2);
+#else
+    Expression *e = new CallExp(loc, new DotIdExp(loc, e2, Id::cmp), e1);
+#endif
+
+    fop->fbody = new ReturnStatement(loc, e);
+
+    unsigned errors = global.startGagging();    // Do not report errors
+    Scope *sc2 = sc->push();
+    sc2->stc = 0;
+    sc2->linkage = LINKd;
+
+    fop->semantic(sc2);
+    fop->semantic2(sc2);
+
+    sc2->pop();
+    if (global.endGagging(errors))    // if errors happened
+        fop = sd->xerrcmp;
+
+    return fop;
+}
+
+/*******************************************
+ * We need a toHash for the struct if
+ * any fields has a toHash.
+ * Generate one if a user-specified one does not exist.
+ */
+bool needToHash(StructDeclaration *sd)
+{
+    //printf("StructDeclaration::needToHash() %s\n", sd->toChars());
+    if (sd->isUnionDeclaration())
+        goto Ldontneed;
+
+    if (sd->xhash)
+        goto Lneed;
+
+    /* If any of the fields has an opEquals, then we
+     * need it too.
+     */
+    for (size_t i = 0; i < sd->fields.dim; i++)
+    {
+        VarDeclaration *v = sd->fields[i];
+        if (v->storage_class & STCref)
+            continue;
+        if (v->overlapped)
+            continue;
+        Type *tv = v->type->toBasetype();
+        Type *tvbase = tv->baseElemOf();
+        if (tvbase->ty == Tstruct)
+        {
+            TypeStruct *ts = (TypeStruct *)tvbase;
+            if (ts->sym->isUnionDeclaration())
+                continue;
+            if (needToHash(ts->sym))
+                goto Lneed;
+            if (ts->sym->aliasthis)     // Bugzilla 14948
+                goto Lneed;
+        }
+        if (tv->isfloating())
+        {
+            // This is necessray for:
+            //  1. comparison of +0.0 and -0.0 should be true.
+            goto Lneed;
+        }
+        if (tv->ty == Tarray)
+            goto Lneed;
+        if (tv->ty == Taarray)
+            goto Lneed;
+        if (tv->ty == Tclass)
+            goto Lneed;
+    }
+Ldontneed:
+    //printf("\tdontneed\n");
+    return false;
+
+Lneed:
+    //printf("\tneed\n");
+    return true;
+}
+
+/******************************************
+ * Build __xtoHash for non-bitwise hashing
+ *      static hash_t xtoHash(ref const S p) nothrow @trusted;
+ */
+FuncDeclaration *buildXtoHash(StructDeclaration *sd, Scope *sc)
+{
+    if (Dsymbol *s = search_function(sd, Id::tohash))
+    {
+        static TypeFunction *tftohash;
+        if (!tftohash)
+        {
+            tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd);
+            tftohash->mod = MODconst;
+            tftohash = (TypeFunction *)tftohash->merge();
+        }
+
+        if (FuncDeclaration *fd = s->isFuncDeclaration())
+        {
+            fd = fd->overloadExactMatch(tftohash);
+            if (fd)
+                return fd;
+        }
+    }
+
+    if (!needToHash(sd))
+        return NULL;
+
+    //printf("StructDeclaration::buildXtoHash() %s\n", sd->toPrettyChars());
+    Loc declLoc = Loc();    // loc is unnecessary so __xtoHash is never called directly
+    Loc loc = Loc();        // internal code should have no loc to prevent coverage
+
+    Parameters *parameters = new Parameters();
+    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
+    TypeFunction *tf = new TypeFunction(parameters, Type::thash_t, 0, LINKd, STCnothrow | STCtrusted);
+
+    Identifier *id = Id::xtoHash;
+    FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);
+    fop->generated = true;
+
+    /* Do memberwise hashing.
+     *
+     * If sd is a nested struct, and if it's nested in a class, the calculated
+     * hash value will also contain the result of parent class's toHash().
+     */
+    const char *code =
+        "size_t h = 0;"
+        "foreach (i, T; typeof(p.tupleof))"
+        "    h += typeid(T).getHash(cast(const void*)&p.tupleof[i]);"
+        "return h;";
+    fop->fbody = new CompileStatement(loc, new StringExp(loc, (char *)code));
+
+    Scope *sc2 = sc->push();
+    sc2->stc = 0;
+    sc2->linkage = LINKd;
+
+    fop->semantic(sc2);
+    fop->semantic2(sc2);
+
+    sc2->pop();
+
+    //printf("%s fop = %s %s\n", sd->toChars(), fop->toChars(), fop->type->toChars());
+    return fop;
+}
+
+/*****************************************
+ * Create inclusive postblit for struct by aggregating
+ * all the postblits in postblits[] with the postblits for
+ * all the members.
+ * Note the close similarity with AggregateDeclaration::buildDtor(),
+ * and the ordering changes (runs forward instead of backwards).
+ */
+FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
+{
+    //printf("StructDeclaration::buildPostBlit() %s\n", sd->toChars());
+    if (sd->isUnionDeclaration())
+        return NULL;
+
+    StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
+    Loc declLoc = sd->postblits.dim ? sd->postblits[0]->loc : sd->loc;
+    Loc loc = Loc();    // internal code should have no loc to prevent coverage
+
+    for (size_t i = 0; i < sd->postblits.dim; i++)
+    {
+        stc |= sd->postblits[i]->storage_class & STCdisable;
+    }
+
+    Statements *a = NULL;
+    for (size_t i = 0; i < sd->fields.dim && !(stc & STCdisable); i++)
+    {
+        VarDeclaration *v = sd->fields[i];
+        if (v->storage_class & STCref)
+            continue;
+        if (v->overlapped)
+            continue;
+        Type *tv = v->type->baseElemOf();
+        if (tv->ty != Tstruct)
+            continue;
+        StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
+        if (!sdv->postblit)
+            continue;
+        assert(!sdv->isUnionDeclaration());
+        sdv->postblit->functionSemantic();
+
+        stc = mergeFuncAttrs(stc, sdv->postblit);
+        stc = mergeFuncAttrs(stc, sdv->dtor);
+        if (stc & STCdisable)
+        {
+            a = NULL;
+            break;
+        }
+        if (!a)
+            a = new Statements();
+
+        Expression *ex = NULL;
+        tv = v->type->toBasetype();
+        if (tv->ty == Tstruct)
+        {
+            // this.v.__xpostblit()
+
+            ex = new ThisExp(loc);
+            ex = new DotVarExp(loc, ex, v);
+
+            // This is a hack so we can call postblits on const/immutable objects.
+            ex = new AddrExp(loc, ex);
+            ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
+            ex = new PtrExp(loc, ex);
+            if (stc & STCsafe)
+                stc = (stc & ~STCsafe) | STCtrusted;
+
+            ex = new DotVarExp(loc, ex, sdv->postblit, false);
+            ex = new CallExp(loc, ex);
+        }
+        else
+        {
+            // _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])
+
+            uinteger_t n = 1;
+            while (tv->ty == Tsarray)
+            {
+                n *= ((TypeSArray *)tv)->dim->toUInteger();
+                tv = tv->nextOf()->toBasetype();
+            }
+            if (n == 0)
+                continue;
+
+            ex = new ThisExp(loc);
+            ex = new DotVarExp(loc, ex, v);
+
+            // This is a hack so we can call postblits on const/immutable objects.
+            ex = new DotIdExp(loc, ex, Id::ptr);
+            ex = new CastExp(loc, ex, sdv->type->pointerTo());
+            if (stc & STCsafe)
+                stc = (stc & ~STCsafe) | STCtrusted;
+
+            ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
+                                       new IntegerExp(loc, n, Type::tsize_t));
+            // Prevent redundant bounds check
+            ((SliceExp *)ex)->upperIsInBounds = true;
+            ((SliceExp *)ex)->lowerIsLessThanUpper = true;
+
+            ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayPostblit), ex);
+        }
+        a->push(new ExpStatement(loc, ex)); // combine in forward order
+
+        /* Bugzilla 10972: When the following field postblit calls fail,
+         * this field should be destructed for Exception Safety.
+         */
+        if (!sdv->dtor)
+            continue;
+        sdv->dtor->functionSemantic();
+
+        tv = v->type->toBasetype();
+        if (v->type->toBasetype()->ty == Tstruct)
+        {
+            // this.v.__xdtor()
+
+            ex = new ThisExp(loc);
+            ex = new DotVarExp(loc, ex, v);
+
+            // This is a hack so we can call destructors on const/immutable objects.
+            ex = new AddrExp(loc, ex);
+            ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
+            ex = new PtrExp(loc, ex);
+            if (stc & STCsafe)
+                stc = (stc & ~STCsafe) | STCtrusted;
+
+            ex = new DotVarExp(loc, ex, sdv->dtor, false);
+            ex = new CallExp(loc, ex);
+        }
+        else
+        {
+            // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
+
+            uinteger_t n = 1;
+            while (tv->ty == Tsarray)
+            {
+                n *= ((TypeSArray *)tv)->dim->toUInteger();
+                tv = tv->nextOf()->toBasetype();
+            }
+            //if (n == 0)
+            //    continue;
+
+            ex = new ThisExp(loc);
+            ex = new DotVarExp(loc, ex, v);
+
+            // This is a hack so we can call destructors on const/immutable objects.
+            ex = new DotIdExp(loc, ex, Id::ptr);
+            ex = new CastExp(loc, ex, sdv->type->pointerTo());
+            if (stc & STCsafe)
+                stc = (stc & ~STCsafe) | STCtrusted;
+
+            ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
+                                       new IntegerExp(loc, n, Type::tsize_t));
+            // Prevent redundant bounds check
+            ((SliceExp *)ex)->upperIsInBounds = true;
+            ((SliceExp *)ex)->lowerIsLessThanUpper = true;
+
+            ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), ex);
+        }
+        a->push(new OnScopeStatement(loc, TOKon_scope_failure, new ExpStatement(loc, ex)));
+    }
+
+    /* Build our own "postblit" which executes a
+     */
+    if (a || (stc & STCdisable))
+    {
+        //printf("Building __fieldPostBlit()\n");
+        PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__fieldPostblit);
+        dd->storage_class |= STCinference;
+        dd->generated = true;
+        dd->fbody = a ? new CompoundStatement(loc, a) : NULL;
+        sd->postblits.shift(dd);
+        sd->members->push(dd);
+        dd->semantic(sc);
+    }
+
+    FuncDeclaration *xpostblit = NULL;
+    switch (sd->postblits.dim)
+    {
+        case 0:
+            break;
+
+        case 1:
+            xpostblit = sd->postblits[0];
+            break;
+
+        default:
+            Expression *e = NULL;
+            stc = STCsafe | STCnothrow | STCpure | STCnogc;
+            for (size_t i = 0; i < sd->postblits.dim; i++)
+            {
+                FuncDeclaration *fd = sd->postblits[i];
+                stc = mergeFuncAttrs(stc, fd);
+                if (stc & STCdisable)
+                {
+                    e = NULL;
+                    break;
+                }
+                Expression *ex = new ThisExp(loc);
+                ex = new DotVarExp(loc, ex, fd, false);
+                ex = new CallExp(loc, ex);
+                e = Expression::combine(e, ex);
+            }
+            PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__aggrPostblit);
+            dd->storage_class |= STCinference;
+            dd->fbody = new ExpStatement(loc, e);
+            sd->members->push(dd);
+            dd->semantic(sc);
+            xpostblit = dd;
+            break;
+    }
+    // Add an __xpostblit alias to make the inclusive postblit accessible
+    if (xpostblit)
+    {
+        AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xpostblit, xpostblit);
+        alias->semantic(sc);
+        sd->members->push(alias);
+        alias->addMember(sc, sd); // add to symbol table
+    }
+    return xpostblit;
+}
+
+/*****************************************
+ * Create inclusive destructor for struct/class by aggregating
+ * all the destructors in dtors[] with the destructors for
+ * all the members.
+ * Note the close similarity with StructDeclaration::buildPostBlit(),
+ * and the ordering changes (runs backward instead of forwards).
+ */
+FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc)
+{
+    //printf("AggregateDeclaration::buildDtor() %s\n", ad->toChars());
+    if (ad->isUnionDeclaration())
+        return NULL;
+
+    StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
+    Loc declLoc = ad->dtors.dim ? ad->dtors[0]->loc : ad->loc;
+    Loc loc = Loc();    // internal code should have no loc to prevent coverage
+
+    Expression *e = NULL;
+    for (size_t i = 0; i < ad->fields.dim; i++)
+    {
+        VarDeclaration *v = ad->fields[i];
+        if (v->storage_class & STCref)
+            continue;
+        if (v->overlapped)
+            continue;
+        Type *tv = v->type->baseElemOf();
+        if (tv->ty != Tstruct)
+            continue;
+        StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
+        if (!sdv->dtor)
+            continue;
+        sdv->dtor->functionSemantic();
+
+        stc = mergeFuncAttrs(stc, sdv->dtor);
+        if (stc & STCdisable)
+        {
+            e = NULL;
+            break;
+        }
+
+        Expression *ex = NULL;
+        tv = v->type->toBasetype();
+        if (tv->ty == Tstruct)
+        {
+            // this.v.__xdtor()
+
+            ex = new ThisExp(loc);
+            ex = new DotVarExp(loc, ex, v);
+
+            // This is a hack so we can call destructors on const/immutable objects.
+            ex = new AddrExp(loc, ex);
+            ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
+            ex = new PtrExp(loc, ex);
+            if (stc & STCsafe)
+                stc = (stc & ~STCsafe) | STCtrusted;
+
+            ex = new DotVarExp(loc, ex, sdv->dtor, false);
+            ex = new CallExp(loc, ex);
+        }
+        else
+        {
+            // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
+
+            uinteger_t n = 1;
+            while (tv->ty == Tsarray)
+            {
+                n *= ((TypeSArray *)tv)->dim->toUInteger();
+                tv = tv->nextOf()->toBasetype();
+            }
+            if (n == 0)
+                continue;
+
+            ex = new ThisExp(loc);
+            ex = new DotVarExp(loc, ex, v);
+
+            // This is a hack so we can call destructors on const/immutable objects.
+            ex = new DotIdExp(loc, ex, Id::ptr);
+            ex = new CastExp(loc, ex, sdv->type->pointerTo());
+            if (stc & STCsafe)
+                stc = (stc & ~STCsafe) | STCtrusted;
+
+            ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
+                                       new IntegerExp(loc, n, Type::tsize_t));
+            // Prevent redundant bounds check
+            ((SliceExp *)ex)->upperIsInBounds = true;
+            ((SliceExp *)ex)->lowerIsLessThanUpper = true;
+
+            ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), ex);
+        }
+        e = Expression::combine(ex, e); // combine in reverse order
+    }
+
+    /* Build our own "destructor" which executes e
+     */
+    if (e || (stc & STCdisable))
+    {
+        //printf("Building __fieldDtor()\n");
+        DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__fieldDtor);
+        dd->storage_class |= STCinference;
+        dd->fbody = new ExpStatement(loc, e);
+        ad->dtors.shift(dd);
+        ad->members->push(dd);
+        dd->semantic(sc);
+    }
+
+    FuncDeclaration *xdtor = NULL;
+    switch (ad->dtors.dim)
+    {
+        case 0:
+            break;
+
+        case 1:
+            xdtor = ad->dtors[0];
+            break;
+
+        default:
+            e = NULL;
+            stc = STCsafe | STCnothrow | STCpure | STCnogc;
+            for (size_t i = 0; i < ad->dtors.dim; i++)
+            {
+                FuncDeclaration *fd = ad->dtors[i];
+                stc = mergeFuncAttrs(stc, fd);
+                if (stc & STCdisable)
+                {
+                    e = NULL;
+                    break;
+                }
+                Expression *ex = new ThisExp(loc);
+                ex = new DotVarExp(loc, ex, fd, false);
+                ex = new CallExp(loc, ex);
+                e = Expression::combine(ex, e);
+            }
+            DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__aggrDtor);
+            dd->storage_class |= STCinference;
+            dd->fbody = new ExpStatement(loc, e);
+            ad->members->push(dd);
+            dd->semantic(sc);
+            xdtor = dd;
+            break;
+    }
+    // Add an __xdtor alias to make the inclusive dtor accessible
+    if (xdtor)
+    {
+        AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xdtor, xdtor);
+        alias->semantic(sc);
+        ad->members->push(alias);
+        alias->addMember(sc, ad); // add to symbol table
+    }
+    return xdtor;
+}
+
+/******************************************
+ * Create inclusive invariant for struct/class by aggregating
+ * all the invariants in invs[].
+ *      void __invariant() const [pure nothrow @trusted]
+ *      {
+ *          invs[0](), invs[1](), ...;
+ *      }
+ */
+FuncDeclaration *buildInv(AggregateDeclaration *ad, Scope *sc)
+{
+    StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
+    Loc declLoc = ad->loc;
+    Loc loc = Loc();    // internal code should have no loc to prevent coverage
+
+    switch (ad->invs.dim)
+    {
+        case 0:
+            return NULL;
+
+        case 1:
+            // Don't return invs[0] so it has uniquely generated name.
+            /* fall through */
+
+        default:
+            Expression *e = NULL;
+            StorageClass stcx = 0;
+            for (size_t i = 0; i < ad->invs.dim; i++)
+            {
+                stc = mergeFuncAttrs(stc, ad->invs[i]);
+                if (stc & STCdisable)
+                {
+                    // What should do?
+                }
+                StorageClass stcy = (ad->invs[i]->storage_class & STCsynchronized) |
+                                    (ad->invs[i]->type->mod & MODshared ? STCshared : 0);
+                if (i == 0)
+                    stcx = stcy;
+                else if (stcx ^ stcy)
+                {
+            #if 1   // currently rejects
+                    ad->error(ad->invs[i]->loc, "mixing invariants with shared/synchronized differene is not supported");
+                    e = NULL;
+                    break;
+            #endif
+                }
+                e = Expression::combine(e, new CallExp(loc, new VarExp(loc, ad->invs[i], false)));
+            }
+            InvariantDeclaration *inv;
+            inv = new InvariantDeclaration(declLoc, Loc(), stc | stcx, Id::classInvariant);
+            inv->fbody = new ExpStatement(loc, e);
+            ad->members->push(inv);
+            inv->semantic(sc);
+            return inv;
+    }
+}
diff --git a/gcc/d/dfrontend/complex_t.h b/gcc/d/dfrontend/complex_t.h
new file mode 100644
index 00000000000..a1ad38890c7
--- /dev/null
+++ b/gcc/d/dfrontend/complex_t.h
@@ -0,0 +1,75 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/complex_t.h
+ */
+
+#ifndef DMD_COMPLEX_T_H
+#define DMD_COMPLEX_T_H
+
+#include "ctfloat.h"
+
+/* Roll our own complex type for compilers that don't support complex
+ */
+
+struct complex_t
+{
+    real_t re;
+    real_t im;
+
+    complex_t(real_t re) : re(re), im(ldouble(0)) {}
+    complex_t(real_t re, real_t im) : re(re), im(im) {}
+
+    complex_t operator + (complex_t y) { return complex_t(re + y.re, im + y.im); }
+    complex_t operator - (complex_t y) { return complex_t(re - y.re, im - y.im); }
+    complex_t operator - () { return complex_t(-re, -im); }
+    complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); }
+
+    complex_t operator / (complex_t y)
+    {
+        if (CTFloat::fabs(y.re) < CTFloat::fabs(y.im))
+        {
+            real_t r = y.re / y.im;
+            real_t den = y.im + r * y.re;
+            return complex_t((re * r + im) / den,
+                             (im * r - re) / den);
+        }
+        else
+        {
+            real_t r = y.im / y.re;
+            real_t den = y.re + r * y.im;
+            return complex_t((re + r * im) / den,
+                             (im - r * re) / den);
+        }
+    }
+
+    operator bool () { return re || im; }
+
+    int operator == (complex_t y) { return re == y.re && im == y.im; }
+    int operator != (complex_t y) { return re != y.re || im != y.im; }
+
+private:
+    complex_t() : re(ldouble(0)), im(ldouble(0)) {}
+};
+
+inline complex_t operator * (real_t x, complex_t y) { return complex_t(x) * y; }
+inline complex_t operator * (complex_t x, real_t y) { return x * complex_t(y); }
+inline complex_t operator / (complex_t x, real_t y) { return x / complex_t(y); }
+
+
+inline real_t creall(complex_t x)
+{
+    return x.re;
+}
+
+inline real_t cimagl(complex_t x)
+{
+    return x.im;
+}
+
+#endif
diff --git a/gcc/d/dfrontend/cond.c b/gcc/d/dfrontend/cond.c
new file mode 100644
index 00000000000..8ae1af067e6
--- /dev/null
+++ b/gcc/d/dfrontend/cond.c
@@ -0,0 +1,376 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/cond.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>                     // strcmp()
+
+#include "id.h"
+#include "init.h"
+#include "declaration.h"
+#include "identifier.h"
+#include "expression.h"
+#include "cond.h"
+#include "module.h"
+#include "template.h"
+#include "mtype.h"
+#include "scope.h"
+#include "arraytypes.h"
+#include "tokens.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
+
+int findCondition(Strings *ids, Identifier *ident)
+{
+    if (ids)
+    {
+        for (size_t i = 0; i < ids->dim; i++)
+        {
+            const char *id = (*ids)[i];
+
+            if (strcmp(id, ident->toChars()) == 0)
+                return true;
+        }
+    }
+
+    return false;
+}
+
+/* ============================================================ */
+
+Condition::Condition(Loc loc)
+{
+    this->loc = loc;
+    inc = 0;
+}
+
+/* ============================================================ */
+
+DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
+        : Condition(Loc())
+{
+    this->mod = mod;
+    this->level = level;
+    this->ident = ident;
+}
+
+Condition *DVCondition::syntaxCopy()
+{
+    return this;        // don't need to copy
+}
+
+/* ============================================================ */
+
+void DebugCondition::setGlobalLevel(unsigned level)
+{
+    global.params.debuglevel = level;
+}
+
+void DebugCondition::addGlobalIdent(const char *ident)
+{
+    if (!global.params.debugids)
+        global.params.debugids = new Strings();
+    global.params.debugids->push((char *)ident);
+}
+
+
+DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
+    : DVCondition(mod, level, ident)
+{
+}
+
+// Helper for printing dependency information
+void printDepsConditional(Scope *sc, DVCondition* condition, const char* depType)
+{
+    if (!global.params.moduleDeps || global.params.moduleDepsFile)
+        return;
+    OutBuffer *ob = global.params.moduleDeps;
+    Module* imod = sc ? sc->instantiatingModule() : condition->mod;
+    if (!imod)
+        return;
+    ob->writestring(depType);
+    ob->writestring(imod->toPrettyChars());
+    ob->writestring(" (");
+    escapePath(ob, imod->srcfile->toChars());
+    ob->writestring(") : ");
+    if (condition->ident)
+        ob->printf("%s\n", condition->ident->toChars());
+    else
+        ob->printf("%d\n", condition->level);
+}
+
+
+int DebugCondition::include(Scope *sc, ScopeDsymbol *sds)
+{
+    //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
+    if (inc == 0)
+    {
+        inc = 2;
+        bool definedInModule = false;
+        if (ident)
+        {
+            if (findCondition(mod->debugids, ident))
+            {
+                inc = 1;
+                definedInModule = true;
+            }
+            else if (findCondition(global.params.debugids, ident))
+                inc = 1;
+            else
+            {   if (!mod->debugidsNot)
+                    mod->debugidsNot = new Strings();
+                mod->debugidsNot->push(ident->toChars());
+            }
+        }
+        else if (level <= global.params.debuglevel || level <= mod->debuglevel)
+            inc = 1;
+        if (!definedInModule)
+            printDepsConditional(sc, this, "depsDebug ");
+    }
+    return (inc == 1);
+}
+
+/* ============================================================ */
+
+void VersionCondition::setGlobalLevel(unsigned level)
+{
+    global.params.versionlevel = level;
+}
+
+static bool isReserved(const char *ident)
+{
+    static const char* reserved[] =
+    {
+        "DigitalMars",
+        "GNU",
+        "LDC",
+        "SDC",
+        "Windows",
+        "Win32",
+        "Win64",
+        "linux",
+        "OSX",
+        "FreeBSD",
+        "OpenBSD",
+        "NetBSD",
+        "DragonFlyBSD",
+        "BSD",
+        "Solaris",
+        "Posix",
+        "AIX",
+        "Haiku",
+        "SkyOS",
+        "SysV3",
+        "SysV4",
+        "Hurd",
+        "Android",
+        "Cygwin",
+        "MinGW",
+        "FreeStanding",
+        "X86",
+        "X86_64",
+        "ARM",
+        "ARM_Thumb",
+        "ARM_SoftFloat",
+        "ARM_SoftFP",
+        "ARM_HardFloat",
+        "AArch64",
+        "Epiphany",
+        "PPC",
+        "PPC_SoftFloat",
+        "PPC_HardFloat",
+        "PPC64",
+        "IA64",
+        "MIPS32",
+        "MIPS64",
+        "MIPS_O32",
+        "MIPS_N32",
+        "MIPS_O64",
+        "MIPS_N64",
+        "MIPS_EABI",
+        "MIPS_SoftFloat",
+        "MIPS_HardFloat",
+        "NVPTX",
+        "NVPTX64",
+        "SPARC",
+        "SPARC_V8Plus",
+        "SPARC_SoftFloat",
+        "SPARC_HardFloat",
+        "SPARC64",
+        "S390",
+        "S390X",
+        "HPPA",
+        "HPPA64",
+        "SH",
+        "Alpha",
+        "Alpha_SoftFloat",
+        "Alpha_HardFloat",
+        "LittleEndian",
+        "BigEndian",
+        "ELFv1",
+        "ELFv2",
+        "CRuntime_Digitalmars",
+        "CRuntime_Glibc",
+        "CRuntime_Microsoft",
+        "D_Coverage",
+        "D_Ddoc",
+        "D_InlineAsm_X86",
+        "D_InlineAsm_X86_64",
+        "D_LP64",
+        "D_X32",
+        "D_HardFloat",
+        "D_SoftFloat",
+        "D_PIC",
+        "D_SIMD",
+        "D_Version2",
+        "D_NoBoundsChecks",
+        "unittest",
+        "assert",
+        "all",
+        "none",
+        NULL
+    };
+
+    for (unsigned i = 0; reserved[i]; i++)
+    {
+        if (strcmp(ident, reserved[i]) == 0)
+            return true;
+    }
+
+    if (ident[0] == 'D' && ident[1] == '_')
+        return true;
+    return false;
+}
+
+void checkReserved(Loc loc, const char *ident)
+{
+    if (isReserved(ident))
+        error(loc, "version identifier '%s' is reserved and cannot be set", ident);
+}
+
+void VersionCondition::addGlobalIdent(const char *ident)
+{
+    checkReserved(Loc(), ident);
+    addPredefinedGlobalIdent(ident);
+}
+
+void VersionCondition::addPredefinedGlobalIdent(const char *ident)
+{
+    if (!global.params.versionids)
+        global.params.versionids = new Strings();
+    global.params.versionids->push((char *)ident);
+}
+
+
+VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
+    : DVCondition(mod, level, ident)
+{
+}
+
+int VersionCondition::include(Scope *sc, ScopeDsymbol *sds)
+{
+    //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
+    //if (ident) printf("\tident = '%s'\n", ident->toChars());
+    if (inc == 0)
+    {
+        inc = 2;
+        bool definedInModule=false;
+        if (ident)
+        {
+            if (findCondition(mod->versionids, ident))
+            {
+                inc = 1;
+                definedInModule = true;
+            }
+            else if (findCondition(global.params.versionids, ident))
+                inc = 1;
+            else
+            {
+                if (!mod->versionidsNot)
+                    mod->versionidsNot = new Strings();
+                mod->versionidsNot->push(ident->toChars());
+            }
+        }
+        else if (level <= global.params.versionlevel || level <= mod->versionlevel)
+            inc = 1;
+        if (!definedInModule && (!ident || (!isReserved(ident->toChars()) && ident != Id::_unittest && ident != Id::_assert)))
+            printDepsConditional(sc, this, "depsVersion ");
+    }
+    return (inc == 1);
+}
+
+/**************************** StaticIfCondition *******************************/
+
+StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
+    : Condition(loc)
+{
+    this->exp = exp;
+    this->nest = 0;
+}
+
+Condition *StaticIfCondition::syntaxCopy()
+{
+    return new StaticIfCondition(loc, exp->syntaxCopy());
+}
+
+int StaticIfCondition::include(Scope *sc, ScopeDsymbol *sds)
+{
+#if 0
+    printf("StaticIfCondition::include(sc = %p, sds = %p) this=%p inc = %d\n", sc, sds, this, inc);
+    if (sds)
+    {
+        printf("\ts = '%s', kind = %s\n", sds->toChars(), sds->kind());
+    }
+#endif
+    if (inc == 0)
+    {
+        if (exp->op == TOKerror || nest > 100)
+        {
+            error(loc, (nest > 1000) ? "unresolvable circular static if expression"
+                                     : "error evaluating static if expression");
+            goto Lerror;
+        }
+
+        if (!sc)
+        {
+            error(loc, "static if conditional cannot be at global scope");
+            inc = 2;
+            return 0;
+        }
+
+        ++nest;
+        sc = sc->push(sc->scopesym);
+        sc->sds = sds;                  // sds gets any addMember()
+
+        bool errors = false;
+        bool result = evalStaticCondition(sc, exp, exp, errors);
+        sc->pop();
+        --nest;
+
+        // Prevent repeated condition evaluation.
+        // See: fail_compilation/fail7815.d
+        if (inc != 0)
+            return (inc == 1);
+        if (errors)
+            goto Lerror;
+        if (result)
+            inc = 1;
+        else
+            inc = 2;
+    }
+    return (inc == 1);
+
+Lerror:
+    if (!global.gag)
+        inc = 2;                // so we don't see the error message again
+    return 0;
+}
diff --git a/gcc/d/dfrontend/cond.h b/gcc/d/dfrontend/cond.h
new file mode 100644
index 00000000000..29af4cab784
--- /dev/null
+++ b/gcc/d/dfrontend/cond.h
@@ -0,0 +1,111 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/cond.h
+ */
+
+#ifndef DMD_DEBCOND_H
+#define DMD_DEBCOND_H
+
+#include "globals.h"
+#include "visitor.h"
+
+class Expression;
+class Identifier;
+struct OutBuffer;
+class Module;
+struct Scope;
+class ScopeDsymbol;
+class DebugCondition;
+class ForeachStatement;
+class ForeachRangeStatement;
+
+int findCondition(Strings *ids, Identifier *ident);
+
+class Condition
+{
+public:
+    Loc loc;
+    // 0: not computed yet
+    // 1: include
+    // 2: do not include
+    int inc;
+
+    Condition(Loc loc);
+
+    virtual Condition *syntaxCopy() = 0;
+    virtual int include(Scope *sc, ScopeDsymbol *sds) = 0;
+    virtual DebugCondition *isDebugCondition() { return NULL; }
+    virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticForeach
+{
+public:
+    Loc loc;
+
+    ForeachStatement *aggrfe;
+    ForeachRangeStatement *rangefe;
+
+    bool needExpansion;
+
+    Condition *syntaxCopy();
+};
+
+class DVCondition : public Condition
+{
+public:
+    unsigned level;
+    Identifier *ident;
+    Module *mod;
+
+    DVCondition(Module *mod, unsigned level, Identifier *ident);
+
+    Condition *syntaxCopy();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DebugCondition : public DVCondition
+{
+public:
+    static void setGlobalLevel(unsigned level);
+    static void addGlobalIdent(const char *ident);
+
+    DebugCondition(Module *mod, unsigned level, Identifier *ident);
+
+    int include(Scope *sc, ScopeDsymbol *sds);
+    DebugCondition *isDebugCondition() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class VersionCondition : public DVCondition
+{
+public:
+    static void setGlobalLevel(unsigned level);
+    static void addGlobalIdent(const char *ident);
+    static void addPredefinedGlobalIdent(const char *ident);
+
+    VersionCondition(Module *mod, unsigned level, Identifier *ident);
+
+    int include(Scope *sc, ScopeDsymbol *sds);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticIfCondition : public Condition
+{
+public:
+    Expression *exp;
+    int nest;         // limit circular dependencies
+
+    StaticIfCondition(Loc loc, Expression *exp);
+    Condition *syntaxCopy();
+    int include(Scope *sc, ScopeDsymbol *sds);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#endif
diff --git a/gcc/d/dfrontend/constfold.c b/gcc/d/dfrontend/constfold.c
new file mode 100644
index 00000000000..5ed016be4a0
--- /dev/null
+++ b/gcc/d/dfrontend/constfold.c
@@ -0,0 +1,1950 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/constfold.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>                     // mem{cpy|set|cmp}()
+#include <math.h>
+#include <new>
+
+#include "rmem.h"
+#include "root.h"
+#include "port.h"
+
+#include "mtype.h"
+#include "expression.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "utf.h"
+#include "ctfe.h"
+#include "target.h"
+
+#define LOG 0
+
+int RealEquals(real_t x1, real_t x2);
+
+Expression *expType(Type *type, Expression *e)
+{
+    if (type != e->type)
+    {
+        e = e->copy();
+        e->type = type;
+    }
+    return e;
+}
+
+/* ================================== isConst() ============================== */
+
+int isConst(Expression *e)
+{
+    //printf("Expression::isConst(): %s\n", e->toChars());
+    switch (e->op)
+    {
+        case TOKint64:
+        case TOKfloat64:
+        case TOKcomplex80:
+            return 1;
+        case TOKnull:
+            return 0;
+        case TOKsymoff:
+            return 2;
+        default:
+            return 0;
+    }
+    assert(0);
+    return 0;
+}
+
+/* =============================== constFold() ============================== */
+
+/* The constFold() functions were redundant with the optimize() ones,
+ * and so have been folded in with them.
+ */
+
+/* ========================================================================== */
+
+UnionExp Neg(Type *type, Expression *e1)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    if (e1->type->isreal())
+    {
+        new(&ue) RealExp(loc, -e1->toReal(), type);
+    }
+    else if (e1->type->isimaginary())
+    {
+        new(&ue) RealExp(loc, -e1->toImaginary(), type);
+    }
+    else if (e1->type->iscomplex())
+    {
+        new(&ue) ComplexExp(loc, -e1->toComplex(), type);
+    }
+    else
+    {
+        new(&ue) IntegerExp(loc, -e1->toInteger(), type);
+    }
+    return ue;
+}
+
+UnionExp Com(Type *type, Expression *e1)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    new(&ue) IntegerExp(loc, ~e1->toInteger(), type);
+    return ue;
+}
+
+UnionExp Not(Type *type, Expression *e1)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    new(&ue) IntegerExp(loc, e1->isBool(false) ? 1 : 0, type);
+    return ue;
+}
+
+UnionExp Bool(Type *type, Expression *e1)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    new(&ue) IntegerExp(loc, e1->isBool(true) ? 1 : 0, type);
+    return ue;
+}
+
+UnionExp Add(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+#if LOG
+    printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+#endif
+    if (type->isreal())
+    {
+        new(&ue) RealExp(loc, e1->toReal() + e2->toReal(), type);
+    }
+    else if (type->isimaginary())
+    {
+        new(&ue) RealExp(loc, e1->toImaginary() + e2->toImaginary(), type);
+    }
+    else if (type->iscomplex())
+    {
+        // This rigamarole is necessary so that -0.0 doesn't get
+        // converted to +0.0 by doing an extraneous add with +0.0
+        complex_t c1 = complex_t(CTFloat::zero);
+        real_t r1 = CTFloat::zero;
+        real_t i1 = CTFloat::zero;
+
+        complex_t c2 = complex_t(CTFloat::zero);
+        real_t r2 = CTFloat::zero;
+        real_t i2 = CTFloat::zero;
+
+        complex_t v = complex_t(CTFloat::zero);
+        int x;
+
+        if (e1->type->isreal())
+        {
+            r1 = e1->toReal();
+            x = 0;
+        }
+        else if (e1->type->isimaginary())
+        {
+            i1 = e1->toImaginary();
+            x = 3;
+        }
+        else
+        {
+            c1 = e1->toComplex();
+            x = 6;
+        }
+
+        if (e2->type->isreal())
+        {
+            r2 = e2->toReal();
+        }
+        else if (e2->type->isimaginary())
+        {
+            i2 = e2->toImaginary();
+            x += 1;
+        }
+        else
+        {
+            c2 = e2->toComplex();
+            x += 2;
+        }
+
+        switch (x)
+        {
+        case 0 + 0:
+            v = complex_t(r1 + r2);
+            break;
+        case 0 + 1:
+            v = complex_t(r1, i2);
+            break;
+        case 0 + 2:
+            v = complex_t(r1 + creall(c2), cimagl(c2));
+            break;
+        case 3 + 0:
+            v = complex_t(r2, i1);
+            break;
+        case 3 + 1:
+            v = complex_t(CTFloat::zero, i1 + i2);
+            break;
+        case 3 + 2:
+            v = complex_t(creall(c2), i1 + cimagl(c2));
+            break;
+        case 6 + 0:
+            v = complex_t(creall(c1) + r2, cimagl(c2));
+            break;
+        case 6 + 1:
+            v = complex_t(creall(c1), cimagl(c1) + i2);
+            break;
+        case 6 + 2:
+            v = c1 + c2;
+            break;
+        default:
+            assert(0);
+        }
+        new(&ue) ComplexExp(loc, v, type);
+    }
+    else if (e1->op == TOKsymoff)
+    {
+        SymOffExp *soe = (SymOffExp *)e1;
+        new(&ue) SymOffExp(loc, soe->var, soe->offset + e2->toInteger());
+        ue.exp()->type = type;
+    }
+    else if (e2->op == TOKsymoff)
+    {
+        SymOffExp *soe = (SymOffExp *)e2;
+        new(&ue) SymOffExp(loc, soe->var, soe->offset + e1->toInteger());
+        ue.exp()->type = type;
+    }
+    else
+        new(&ue) IntegerExp(loc, e1->toInteger() + e2->toInteger(), type);
+    return ue;
+}
+
+
+UnionExp Min(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    if (type->isreal())
+    {
+        new(&ue) RealExp(loc, e1->toReal() - e2->toReal(), type);
+    }
+    else if (type->isimaginary())
+    {
+        new(&ue) RealExp(loc, e1->toImaginary() - e2->toImaginary(), type);
+    }
+    else if (type->iscomplex())
+    {
+        // This rigamarole is necessary so that -0.0 doesn't get
+        // converted to +0.0 by doing an extraneous add with +0.0
+        complex_t c1 = complex_t(CTFloat::zero);
+        real_t r1 = CTFloat::zero;
+        real_t i1 = CTFloat::zero;
+
+        complex_t c2 = complex_t(CTFloat::zero);
+        real_t r2 = CTFloat::zero;
+        real_t i2 = CTFloat::zero;
+
+        complex_t v = complex_t(CTFloat::zero);
+        int x;
+
+        if (e1->type->isreal())
+        {
+            r1 = e1->toReal();
+            x = 0;
+        }
+        else if (e1->type->isimaginary())
+        {
+            i1 = e1->toImaginary();
+            x = 3;
+        }
+        else
+        {
+            c1 = e1->toComplex();
+            x = 6;
+        }
+
+        if (e2->type->isreal())
+        {
+            r2 = e2->toReal();
+        }
+        else if (e2->type->isimaginary())
+        {
+            i2 = e2->toImaginary();
+            x += 1;
+        }
+        else
+        {
+            c2 = e2->toComplex();
+            x += 2;
+        }
+
+        switch (x)
+        {
+        case 0 + 0:
+            v = complex_t(r1 - r2);
+            break;
+        case 0 + 1:
+            v = complex_t(r1, -i2);
+            break;
+        case 0 + 2:
+            v = complex_t(r1 - creall(c2), -cimagl(c2));
+            break;
+        case 3 + 0:
+            v = complex_t(-r2, i1);
+            break;
+        case 3 + 1:
+            v = complex_t(CTFloat::zero, i1 - i2);
+            break;
+        case 3 + 2:
+            v = complex_t(-creall(c2), i1 - cimagl(c2));
+            break;
+        case 6 + 0:
+            v = complex_t(creall(c1) - r2, cimagl(c1));
+            break;
+        case 6 + 1:
+            v = complex_t(creall(c1), cimagl(c1) - i2);
+            break;
+        case 6 + 2:
+            v = c1 - c2;
+            break;
+        default:
+            assert(0);
+        }
+        new(&ue) ComplexExp(loc, v, type);
+    }
+    else if (e1->op == TOKsymoff)
+    {
+        SymOffExp *soe = (SymOffExp *)e1;
+        new(&ue) SymOffExp(loc, soe->var, soe->offset - e2->toInteger());
+        ue.exp()->type = type;
+    }
+    else
+    {
+        new(&ue) IntegerExp(loc, e1->toInteger() - e2->toInteger(), type);
+    }
+    return ue;
+}
+
+UnionExp Mul(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {
+        complex_t c = complex_t(CTFloat::zero);
+        real_t r;
+
+        if (e1->type->isreal())
+        {
+            r = e1->toReal();
+            c = e2->toComplex();
+            c = complex_t(r * creall(c), r * cimagl(c));
+        }
+        else if (e1->type->isimaginary())
+        {
+            r = e1->toImaginary();
+            c = e2->toComplex();
+            c = complex_t(-r * cimagl(c), r * creall(c));
+        }
+        else if (e2->type->isreal())
+        {
+            r = e2->toReal();
+            c = e1->toComplex();
+            c = complex_t(r * creall(c), r * cimagl(c));
+        }
+        else if (e2->type->isimaginary())
+        {
+            r = e2->toImaginary();
+            c = e1->toComplex();
+            c = complex_t(-r * cimagl(c), r * creall(c));
+        }
+        else
+            c = e1->toComplex() * e2->toComplex();
+
+        if (type->isreal())
+            new(&ue) RealExp(loc, creall(c), type);
+        else if (type->isimaginary())
+            new(&ue) RealExp(loc, cimagl(c), type);
+        else if (type->iscomplex())
+            new(&ue) ComplexExp(loc, c, type);
+        else
+            assert(0);
+    }
+    else
+    {
+        new(&ue) IntegerExp(loc, e1->toInteger() * e2->toInteger(), type);
+    }
+    return ue;
+}
+
+UnionExp Div(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {
+        complex_t c = complex_t(CTFloat::zero);
+        real_t r;
+
+        //e1->type->print();
+        //e2->type->print();
+        if (e2->type->isreal())
+        {
+            if (e1->type->isreal())
+            {
+                new(&ue) RealExp(loc, e1->toReal() / e2->toReal(), type);
+                return ue;
+            }
+            r = e2->toReal();
+            c = e1->toComplex();
+            c = complex_t(creall(c) / r, cimagl(c) / r);
+        }
+        else if (e2->type->isimaginary())
+        {
+            r = e2->toImaginary();
+            c = e1->toComplex();
+            c = complex_t(cimagl(c) / r, -creall(c) / r);
+        }
+        else
+        {
+            c = e1->toComplex() / e2->toComplex();
+        }
+
+        if (type->isreal())
+            new(&ue) RealExp(loc, creall(c), type);
+        else if (type->isimaginary())
+            new(&ue) RealExp(loc, cimagl(c), type);
+        else if (type->iscomplex())
+            new(&ue) ComplexExp(loc, c, type);
+        else
+            assert(0);
+    }
+    else
+    {
+        sinteger_t n1;
+        sinteger_t n2;
+        sinteger_t n;
+
+        n1 = e1->toInteger();
+        n2 = e2->toInteger();
+        if (n2 == 0)
+        {
+            e2->error("divide by 0");
+            new(&ue) ErrorExp();
+            return ue;
+        }
+        if (n2 == -1 && !type->isunsigned())
+        {
+            // Check for int.min / -1
+            if (n1 == 0xFFFFFFFF80000000UL && type->toBasetype()->ty != Tint64)
+            {
+                e2->error("integer overflow: int.min / -1");
+                new(&ue) ErrorExp();
+                return ue;
+            }
+            else if (n1 == 0x8000000000000000L) // long.min / -1
+            {
+                e2->error("integer overflow: long.min / -1");
+                new(&ue) ErrorExp();
+                return ue;
+            }
+        }
+        if (e1->type->isunsigned() || e2->type->isunsigned())
+            n = ((dinteger_t) n1) / ((dinteger_t) n2);
+        else
+            n = n1 / n2;
+        new(&ue) IntegerExp(loc, n, type);
+    }
+    return ue;
+}
+
+UnionExp Mod(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {
+        complex_t c = complex_t(CTFloat::zero);
+
+        if (e2->type->isreal())
+        {
+            real_t r2 = e2->toReal();
+
+            c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2);
+        }
+        else if (e2->type->isimaginary())
+        {
+            real_t i2 = e2->toImaginary();
+
+            c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2);
+        }
+        else
+            assert(0);
+
+        if (type->isreal())
+            new(&ue) RealExp(loc, creall(c), type);
+        else if (type->isimaginary())
+            new(&ue) RealExp(loc, cimagl(c), type);
+        else if (type->iscomplex())
+            new(&ue) ComplexExp(loc, c, type);
+        else
+            assert(0);
+    }
+    else
+    {
+        sinteger_t n1;
+        sinteger_t n2;
+        sinteger_t n;
+
+        n1 = e1->toInteger();
+        n2 = e2->toInteger();
+        if (n2 == 0)
+        {
+            e2->error("divide by 0");
+            new(&ue) ErrorExp();
+            return ue;
+        }
+        if (n2 == -1 && !type->isunsigned())
+        {
+            // Check for int.min % -1
+            if (n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64)
+            {
+                e2->error("integer overflow: int.min %% -1");
+                new(&ue) ErrorExp();
+                return ue;
+            }
+            else if (n1 == 0x8000000000000000LL) // long.min % -1
+            {
+                e2->error("integer overflow: long.min %% -1");
+                new(&ue) ErrorExp();
+                return ue;
+            }
+        }
+        if (e1->type->isunsigned() || e2->type->isunsigned())
+            n = ((dinteger_t) n1) % ((dinteger_t) n2);
+        else
+            n = n1 % n2;
+        new(&ue) IntegerExp(loc, n, type);
+    }
+    return ue;
+}
+
+UnionExp Pow(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    // Handle integer power operations.
+    if (e2->type->isintegral())
+    {
+        dinteger_t n = e2->toInteger();
+        bool neg;
+
+        if (!e2->type->isunsigned() && (sinteger_t)n < 0)
+        {
+            if (e1->type->isintegral())
+            {
+                new(&ue) CTFEExp(TOKcantexp);
+                return ue;
+            }
+
+            // Don't worry about overflow, from now on n is unsigned.
+            neg = true;
+            n = -n;
+        }
+        else
+            neg = false;
+
+        UnionExp ur, uv;
+        if (e1->type->iscomplex())
+        {
+            new(&ur) ComplexExp(loc, e1->toComplex(), e1->type);
+            new(&uv) ComplexExp(loc, complex_t(CTFloat::one), e1->type);
+        }
+        else if (e1->type->isfloating())
+        {
+            new(&ur) RealExp(loc, e1->toReal(), e1->type);
+            new(&uv) RealExp(loc, CTFloat::one, e1->type);
+        }
+        else
+        {
+            new(&ur) IntegerExp(loc, e1->toInteger(), e1->type);
+            new(&uv) IntegerExp(loc, 1, e1->type);
+        }
+
+        Expression* r = ur.exp();
+        Expression* v = uv.exp();
+        while (n != 0)
+        {
+            if (n & 1)
+            {
+                // v = v * r;
+                uv = Mul(v->type, v, r);
+            }
+            n >>= 1;
+            // r = r * r
+            ur = Mul(r->type, r, r);
+        }
+
+        if (neg)
+        {
+            // ue = 1.0 / v
+            UnionExp one;
+            new(&one) RealExp(loc, CTFloat::one, v->type);
+            uv = Div(v->type, one.exp(), v);
+        }
+
+        if (type->iscomplex())
+            new(&ue) ComplexExp(loc, v->toComplex(), type);
+        else if (type->isintegral())
+            new(&ue) IntegerExp(loc, v->toInteger(), type);
+        else
+            new(&ue) RealExp(loc, v->toReal(), type);
+    }
+    else if (e2->type->isfloating())
+    {
+        // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
+        if (e1->toReal() < CTFloat::zero)
+        {
+            new(&ue) RealExp(loc, Target::RealProperties::nan, type);
+        }
+        else
+            new(&ue) CTFEExp(TOKcantexp);
+    }
+    else
+        new(&ue) CTFEExp(TOKcantexp);
+
+    return ue;
+}
+
+UnionExp Shl(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    new(&ue) IntegerExp(loc, e1->toInteger() << e2->toInteger(), type);
+    return ue;
+}
+
+UnionExp Shr(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    dinteger_t value = e1->toInteger();
+    dinteger_t dcount = e2->toInteger();
+    assert(dcount <= 0xFFFFFFFF);
+    unsigned count = (unsigned)dcount;
+    switch (e1->type->toBasetype()->ty)
+    {
+        case Tint8:
+                value = (d_int8)(value) >> count;
+                break;
+
+        case Tuns8:
+        case Tchar:
+                value = (d_uns8)(value) >> count;
+                break;
+
+        case Tint16:
+                value = (d_int16)(value) >> count;
+                break;
+
+        case Tuns16:
+        case Twchar:
+                value = (d_uns16)(value) >> count;
+                break;
+
+        case Tint32:
+                value = (d_int32)(value) >> count;
+                break;
+
+        case Tuns32:
+        case Tdchar:
+                value = (d_uns32)(value) >> count;
+                break;
+
+        case Tint64:
+                value = (d_int64)(value) >> count;
+                break;
+
+        case Tuns64:
+                value = (d_uns64)(value) >> count;
+                break;
+
+        case Terror:
+                new(&ue) ErrorExp();
+                return ue;
+
+        default:
+                assert(0);
+    }
+    new(&ue) IntegerExp(loc, value, type);
+    return ue;
+}
+
+UnionExp Ushr(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    dinteger_t value = e1->toInteger();
+    dinteger_t dcount = e2->toInteger();
+    assert(dcount <= 0xFFFFFFFF);
+    unsigned count = (unsigned)dcount;
+    switch (e1->type->toBasetype()->ty)
+    {
+        case Tint8:
+        case Tuns8:
+        case Tchar:
+                // Possible only with >>>=. >>> always gets promoted to int.
+                value = (value & 0xFF) >> count;
+                break;
+
+        case Tint16:
+        case Tuns16:
+        case Twchar:
+                // Possible only with >>>=. >>> always gets promoted to int.
+                value = (value & 0xFFFF) >> count;
+                break;
+
+        case Tint32:
+        case Tuns32:
+        case Tdchar:
+                value = (value & 0xFFFFFFFF) >> count;
+                break;
+
+        case Tint64:
+        case Tuns64:
+                value = (d_uns64)(value) >> count;
+                break;
+
+        case Terror:
+                new(&ue) ErrorExp();
+                return ue;
+
+        default:
+                assert(0);
+    }
+    new(&ue) IntegerExp(loc, value, type);
+    return ue;
+}
+
+UnionExp And(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    new(&ue) IntegerExp(e1->loc, e1->toInteger() & e2->toInteger(), type);
+    return ue;
+}
+
+UnionExp Or(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    new(&ue) IntegerExp(e1->loc, e1->toInteger() | e2->toInteger(), type);
+    return ue;
+}
+
+UnionExp Xor(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    new(&ue) IntegerExp(e1->loc, e1->toInteger() ^ e2->toInteger(), type);
+    return ue;
+}
+
+/* Also returns TOKcantexp if cannot be computed.
+ */
+UnionExp Equal(TOK op, Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+    int cmp = 0;
+    real_t r1;
+    real_t r2;
+
+    //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+    assert(op == TOKequal || op == TOKnotequal);
+
+    if (e1->op == TOKnull)
+    {
+        if (e2->op == TOKnull)
+            cmp = 1;
+        else if (e2->op == TOKstring)
+        {
+            StringExp *es2 = (StringExp *)e2;
+            cmp = (0 == es2->len);
+        }
+        else if (e2->op == TOKarrayliteral)
+        {
+            ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+            cmp = !es2->elements || (0 == es2->elements->dim);
+        }
+        else
+        {
+            new(&ue) CTFEExp(TOKcantexp);
+            return ue;
+        }
+    }
+    else if (e2->op == TOKnull)
+    {
+        if (e1->op == TOKstring)
+        {
+            StringExp *es1 = (StringExp *)e1;
+            cmp = (0 == es1->len);
+        }
+        else if (e1->op == TOKarrayliteral)
+        {
+            ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+            cmp = !es1->elements || (0 == es1->elements->dim);
+        }
+        else
+        {
+            new(&ue) CTFEExp(TOKcantexp);
+            return ue;
+        }
+    }
+    else if (e1->op == TOKstring && e2->op == TOKstring)
+    {
+        StringExp *es1 = (StringExp *)e1;
+        StringExp *es2 = (StringExp *)e2;
+
+        if (es1->sz != es2->sz)
+        {
+            assert(global.errors);
+            new(&ue) CTFEExp(TOKcantexp);
+            return ue;
+        }
+        if (es1->len == es2->len &&
+            memcmp(es1->string, es2->string, es1->sz * es1->len) == 0)
+            cmp = 1;
+        else
+            cmp = 0;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral)
+    {
+        ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+        ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+        if ((!es1->elements || !es1->elements->dim) &&
+            (!es2->elements || !es2->elements->dim))
+            cmp = 1;            // both arrays are empty
+        else if (!es1->elements || !es2->elements)
+            cmp = 0;
+        else if (es1->elements->dim != es2->elements->dim)
+            cmp = 0;
+        else
+        {
+            for (size_t i = 0; i < es1->elements->dim; i++)
+            {
+                Expression *ee1 = es1->getElement(i);
+                Expression *ee2 = es2->getElement(i);
+                ue = Equal(TOKequal, Type::tint32, ee1, ee2);
+                if (CTFEExp::isCantExp(ue.exp()))
+                    return ue;
+                cmp = (int)ue.exp()->toInteger();
+                if (cmp == 0)
+                    break;
+            }
+        }
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
+    {
+        // Swap operands and use common code
+        Expression *etmp = e1;
+        e1 = e2;
+        e2 = etmp;
+        goto Lsa;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKarrayliteral)
+    {
+     Lsa:
+        StringExp *es1 = (StringExp *)e1;
+        ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+        size_t dim1 = es1->len;
+        size_t dim2 = es2->elements ? es2->elements->dim : 0;
+        if (dim1 != dim2)
+            cmp = 0;
+        else
+        {
+            cmp = 1;            // if dim1 winds up being 0
+            for (size_t i = 0; i < dim1; i++)
+            {
+                uinteger_t c = es1->charAt(i);
+                Expression *ee2 = es2->getElement(i);
+                if (ee2->isConst() != 1)
+                {
+                    new(&ue) CTFEExp(TOKcantexp);
+                    return ue;
+                }
+                cmp = (c == ee2->toInteger());
+                if (cmp == 0)
+                    break;
+            }
+        }
+    }
+    else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
+    {
+        StructLiteralExp *es1 = (StructLiteralExp *)e1;
+        StructLiteralExp *es2 = (StructLiteralExp *)e2;
+
+        if (es1->sd != es2->sd)
+            cmp = 0;
+        else if ((!es1->elements || !es1->elements->dim) &&
+            (!es2->elements || !es2->elements->dim))
+            cmp = 1;            // both arrays are empty
+        else if (!es1->elements || !es2->elements)
+            cmp = 0;
+        else if (es1->elements->dim != es2->elements->dim)
+            cmp = 0;
+        else
+        {
+            cmp = 1;
+            for (size_t i = 0; i < es1->elements->dim; i++)
+            {
+                Expression *ee1 = (*es1->elements)[i];
+                Expression *ee2 = (*es2->elements)[i];
+
+                if (ee1 == ee2)
+                    continue;
+                if (!ee1 || !ee2)
+                {
+                    cmp = 0;
+                    break;
+                }
+                ue = Equal(TOKequal, Type::tint32, ee1, ee2);
+                if (ue.exp()->op == TOKcantexp)
+                    return ue;
+                cmp = (int)ue.exp()->toInteger();
+                if (cmp == 0)
+                    break;
+            }
+        }
+    }
+    else if (e1->isConst() != 1 || e2->isConst() != 1)
+    {
+        new(&ue) CTFEExp(TOKcantexp);
+        return ue;
+    }
+    else if (e1->type->isreal())
+    {
+        r1 = e1->toReal();
+        r2 = e2->toReal();
+        goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+        r1 = e1->toImaginary();
+        r2 = e2->toImaginary();
+     L1:
+        if (CTFloat::isNaN(r1) || CTFloat::isNaN(r2)) // if unordered
+        {
+            cmp = 0;
+        }
+        else
+        {
+            cmp = (r1 == r2);
+        }
+    }
+    else if (e1->type->iscomplex())
+    {
+        cmp = e1->toComplex() == e2->toComplex();
+    }
+    else if (e1->type->isintegral() || e1->type->toBasetype()->ty == Tpointer)
+    {
+        cmp = (e1->toInteger() == e2->toInteger());
+    }
+    else
+    {
+        new(&ue) CTFEExp(TOKcantexp);
+        return ue;
+    }
+
+    if (op == TOKnotequal)
+        cmp ^= 1;
+    new(&ue) IntegerExp(loc, cmp, type);
+    return ue;
+}
+
+UnionExp Identity(TOK op, Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+    int cmp;
+
+    if (e1->op == TOKnull)
+    {
+        cmp = (e2->op == TOKnull);
+    }
+    else if (e2->op == TOKnull)
+    {
+        cmp = 0;
+    }
+    else if (e1->op == TOKsymoff && e2->op == TOKsymoff)
+    {
+        SymOffExp *es1 = (SymOffExp *)e1;
+        SymOffExp *es2 = (SymOffExp *)e2;
+
+        cmp = (es1->var == es2->var && es1->offset == es2->offset);
+    }
+    else
+    {
+       if (e1->type->isreal())
+       {
+           cmp = RealEquals(e1->toReal(), e2->toReal());
+       }
+       else if (e1->type->isimaginary())
+       {
+           cmp = RealEquals(e1->toImaginary(), e2->toImaginary());
+       }
+       else if (e1->type->iscomplex())
+       {
+           complex_t v1 = e1->toComplex();
+           complex_t v2 = e2->toComplex();
+           cmp = RealEquals(creall(v1), creall(v2)) &&
+                 RealEquals(cimagl(v1), cimagl(v1));
+        }
+        else
+        {
+           ue = Equal((op == TOKidentity) ? TOKequal : TOKnotequal,
+                   type, e1, e2);
+           return ue;
+        }
+    }
+    if (op == TOKnotidentity)
+        cmp ^= 1;
+    new(&ue) IntegerExp(loc, cmp, type);
+    return ue;
+}
+
+
+UnionExp Cmp(TOK op, Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+    dinteger_t n;
+    real_t r1;
+    real_t r2;
+
+    //printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+    if (e1->op == TOKstring && e2->op == TOKstring)
+    {
+        StringExp *es1 = (StringExp *)e1;
+        StringExp *es2 = (StringExp *)e2;
+        size_t sz = es1->sz;
+        assert(sz == es2->sz);
+
+        size_t len = es1->len;
+        if (es2->len < len)
+            len = es2->len;
+
+        int rawCmp = memcmp(es1->string, es2->string, sz * len);
+        if (rawCmp == 0)
+            rawCmp = (int)(es1->len - es2->len);
+        n = specificCmp(op, rawCmp);
+    }
+    else if (e1->isConst() != 1 || e2->isConst() != 1)
+    {
+        new(&ue) CTFEExp(TOKcantexp);
+        return ue;
+    }
+    else if (e1->type->isreal())
+    {
+        r1 = e1->toReal();
+        r2 = e2->toReal();
+        goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+        r1 = e1->toImaginary();
+        r2 = e2->toImaginary();
+     L1:
+        n = realCmp(op, r1, r2);
+    }
+    else if (e1->type->iscomplex())
+    {
+        assert(0);
+    }
+    else
+    {
+        sinteger_t n1;
+        sinteger_t n2;
+
+        n1 = e1->toInteger();
+        n2 = e2->toInteger();
+        if (e1->type->isunsigned() || e2->type->isunsigned())
+            n = intUnsignedCmp(op, n1, n2);
+        else
+            n = intSignedCmp(op, n1, n2);
+    }
+    new(&ue) IntegerExp(loc, n, type);
+    return ue;
+}
+
+/* Also returns TOKcantexp if cannot be computed.
+ *  to: type to cast to
+ *  type: type to paint the result
+ */
+
+UnionExp Cast(Type *type, Type *to, Expression *e1)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    Type *tb = to->toBasetype();
+    Type *typeb = type->toBasetype();
+
+    //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars());
+    //printf("\te1->type = %s\n", e1->type->toChars());
+    if (e1->type->equals(type) && type->equals(to))
+    {
+        new(&ue) UnionExp(e1);
+        return ue;
+    }
+
+    if (e1->op == TOKvector && ((TypeVector *)e1->type)->basetype->equals(type) && type->equals(to))
+    {
+        Expression *ex = ((VectorExp *)e1)->e1;
+        new(&ue) UnionExp(ex);
+        return ue;
+    }
+
+    if (e1->type->implicitConvTo(to) >= MATCHconst ||
+        to->implicitConvTo(e1->type) >= MATCHconst)
+    {
+        goto L1;
+    }
+
+    // Allow covariant converions of delegates
+    // (Perhaps implicit conversion from pure to impure should be a MATCHconst,
+    // then we wouldn't need this extra check.)
+    if (e1->type->toBasetype()->ty == Tdelegate &&
+        e1->type->implicitConvTo(to) == MATCHconvert)
+    {
+        goto L1;
+    }
+
+    /* Allow casting from one string type to another
+     */
+    if (e1->op == TOKstring)
+    {
+        if (tb->ty == Tarray && typeb->ty == Tarray &&
+            tb->nextOf()->size() == typeb->nextOf()->size())
+        {
+            goto L1;
+        }
+    }
+
+    if (e1->op == TOKarrayliteral && typeb == tb)
+    {
+L1:
+        Expression *ex = expType(to, e1);
+        new(&ue) UnionExp(ex);
+        return ue;
+    }
+
+    if (e1->isConst() != 1)
+    {
+        new(&ue) CTFEExp(TOKcantexp);
+    }
+    else if (tb->ty == Tbool)
+    {
+        new(&ue) IntegerExp(loc, e1->toInteger() != 0, type);
+    }
+    else if (type->isintegral())
+    {
+        if (e1->type->isfloating())
+        {
+            dinteger_t result;
+            real_t r = e1->toReal();
+
+            switch (typeb->ty)
+            {
+                case Tint8:
+                    result = (d_int8)(sinteger_t)r;
+                    break;
+                case Tchar:
+                case Tuns8:
+                    result = (d_uns8)(dinteger_t)r;
+                    break;
+                case Tint16:
+                    result = (d_int16)(sinteger_t)r;
+                    break;
+                case Twchar:
+                case Tuns16:
+                    result = (d_uns16)(dinteger_t)r;
+                    break;
+                case Tint32:
+                    result = (d_int32)r;
+                    break;
+                case Tdchar:
+                case Tuns32:
+                    result = (d_uns32)r;
+                    break;
+                case Tint64:
+                    result = (d_int64)r;
+                    break;
+                case Tuns64:
+                    result = (d_uns64)r;
+                    break;
+                default:
+                    assert(0);
+            }
+
+            new(&ue) IntegerExp(loc, result, type);
+        }
+        else if (type->isunsigned())
+            new(&ue) IntegerExp(loc, e1->toUInteger(), type);
+        else
+            new(&ue) IntegerExp(loc, e1->toInteger(), type);
+    }
+    else if (tb->isreal())
+    {
+        real_t value = e1->toReal();
+
+        new(&ue) RealExp(loc, value, type);
+    }
+    else if (tb->isimaginary())
+    {
+        real_t value = e1->toImaginary();
+
+        new(&ue) RealExp(loc, value, type);
+    }
+    else if (tb->iscomplex())
+    {
+        complex_t value = e1->toComplex();
+
+        new(&ue) ComplexExp(loc, value, type);
+    }
+    else if (tb->isscalar())
+    {
+        new(&ue) IntegerExp(loc, e1->toInteger(), type);
+    }
+    else if (tb->ty == Tvoid)
+    {
+        new(&ue) CTFEExp(TOKcantexp);
+    }
+    else if (tb->ty == Tstruct && e1->op == TOKint64)
+    {
+        // Struct = 0;
+        StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration();
+        assert(sd);
+        Expressions *elements = new Expressions;
+        for (size_t i = 0; i < sd->fields.dim; i++)
+        {
+            VarDeclaration *v = sd->fields[i];
+            UnionExp zero;
+            new(&zero) IntegerExp(0);
+            ue = Cast(v->type, v->type, zero.exp());
+            if (ue.exp()->op == TOKcantexp)
+                return ue;
+            elements->push(ue.exp()->copy());
+        }
+        new(&ue) StructLiteralExp(loc, sd, elements);
+        ue.exp()->type = type;
+    }
+    else
+    {
+        if (type != Type::terror)
+        {
+            // have to change to Internal Compiler Error
+            // all invalid casts should be handled already in Expression::castTo().
+            error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars());
+        }
+        new(&ue) ErrorExp();
+    }
+    return ue;
+}
+
+
+UnionExp ArrayLength(Type *type, Expression *e1)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    if (e1->op == TOKstring)
+    {
+        StringExp *es1 = (StringExp *)e1;
+
+        new(&ue) IntegerExp(loc, es1->len, type);
+    }
+    else if (e1->op == TOKarrayliteral)
+    {
+        ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+        size_t dim = ale->elements ? ale->elements->dim : 0;
+
+        new(&ue) IntegerExp(loc, dim, type);
+    }
+    else if (e1->op == TOKassocarrayliteral)
+    {
+        AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1;
+        size_t dim = ale->keys->dim;
+
+        new(&ue) IntegerExp(loc, dim, type);
+    }
+    else if (e1->type->toBasetype()->ty == Tsarray)
+    {
+        Expression *e = ((TypeSArray *)e1->type->toBasetype())->dim;
+        new(&ue) UnionExp(e);
+    }
+    else
+        new(&ue) CTFEExp(TOKcantexp);
+    return ue;
+}
+
+/* Also return TOKcantexp if this fails
+ */
+UnionExp Index(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+    //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+    assert(e1->type);
+    if (e1->op == TOKstring && e2->op == TOKint64)
+    {
+        StringExp *es1 = (StringExp *)e1;
+        uinteger_t i = e2->toInteger();
+
+        if (i >= es1->len)
+        {
+            e1->error("string index %llu is out of bounds [0 .. %llu]", i, (ulonglong)es1->len);
+            new(&ue) ErrorExp();
+        }
+        else
+        {
+            new(&ue) IntegerExp(loc, es1->charAt(i), type);
+        }
+    }
+    else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64)
+    {
+        TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype();
+        uinteger_t length = tsa->dim->toInteger();
+        uinteger_t i = e2->toInteger();
+
+        if (i >= length)
+        {
+            e1->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length);
+            new(&ue) ErrorExp();
+        }
+        else if (e1->op == TOKarrayliteral)
+        {
+            ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+            Expression *e = ale->getElement((size_t)i);
+            e->type = type;
+            e->loc = loc;
+            if (hasSideEffect(e))
+                new(&ue) CTFEExp(TOKcantexp);
+            else
+                new(&ue) UnionExp(e);
+        }
+        else
+            new(&ue) CTFEExp(TOKcantexp);
+    }
+    else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64)
+    {
+        uinteger_t i = e2->toInteger();
+
+        if (e1->op == TOKarrayliteral)
+        {
+            ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+            if (i >= ale->elements->dim)
+            {
+                e1->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
+                new(&ue) ErrorExp();
+            }
+            else
+            {
+                Expression *e = ale->getElement((size_t)i);
+                e->type = type;
+                e->loc = loc;
+                if (hasSideEffect(e))
+                    new(&ue) CTFEExp(TOKcantexp);
+                else
+                    new(&ue) UnionExp(e);
+            }
+        }
+        else
+            new(&ue) CTFEExp(TOKcantexp);
+    }
+    else if (e1->op == TOKassocarrayliteral)
+    {
+        AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1;
+        /* Search the keys backwards, in case there are duplicate keys
+         */
+        for (size_t i = ae->keys->dim; i;)
+        {
+            i--;
+            Expression *ekey = (*ae->keys)[i];
+            ue = Equal(TOKequal, Type::tbool, ekey, e2);
+            if (CTFEExp::isCantExp(ue.exp()))
+                return ue;
+            if (ue.exp()->isBool(true))
+            {
+                Expression *e = (*ae->values)[i];
+                e->type = type;
+                e->loc = loc;
+                if (hasSideEffect(e))
+                    new(&ue) CTFEExp(TOKcantexp);
+                else
+                    new(&ue) UnionExp(e);
+                return ue;
+            }
+        }
+        new(&ue) CTFEExp(TOKcantexp);
+    }
+    else
+        new(&ue) CTFEExp(TOKcantexp);
+    return ue;
+}
+
+/* Also return TOKcantexp if this fails
+ */
+UnionExp Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
+{
+    UnionExp ue;
+    Loc loc = e1->loc;
+
+#if LOG
+    printf("Slice()\n");
+    if (lwr)
+    {
+        printf("\te1 = %s\n", e1->toChars());
+        printf("\tlwr = %s\n", lwr->toChars());
+        printf("\tupr = %s\n", upr->toChars());
+    }
+#endif
+    if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64)
+    {
+        StringExp *es1 = (StringExp *)e1;
+        uinteger_t ilwr = lwr->toInteger();
+        uinteger_t iupr = upr->toInteger();
+
+        if (iupr > es1->len || ilwr > iupr)
+        {
+            e1->error("string slice [%llu .. %llu] is out of bounds", ilwr, iupr);
+            new(&ue) ErrorExp();
+        }
+        else
+        {
+            size_t len = (size_t)(iupr - ilwr);
+            unsigned char sz = es1->sz;
+
+            void *s = mem.xmalloc((len + 1) * sz);
+            memcpy((char *)s, (char *)es1->string + ilwr * sz, len * sz);
+            memset((char *)s + len * sz, 0, sz);
+
+            new(&ue) StringExp(loc, s, len, es1->postfix);
+            StringExp *es = (StringExp *)ue.exp();
+            es->sz = sz;
+            es->committed = es1->committed;
+            es->type = type;
+        }
+    }
+    else if (e1->op == TOKarrayliteral &&
+            lwr->op == TOKint64 && upr->op == TOKint64 &&
+            !hasSideEffect(e1))
+    {
+        ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+        uinteger_t ilwr = lwr->toInteger();
+        uinteger_t iupr = upr->toInteger();
+
+        if (iupr > es1->elements->dim || ilwr > iupr)
+        {
+            e1->error("array slice [%llu .. %llu] is out of bounds", ilwr, iupr);
+            new(&ue) ErrorExp();
+        }
+        else
+        {
+            Expressions *elements = new Expressions();
+            elements->setDim((size_t)(iupr - ilwr));
+            memcpy(elements->tdata(),
+                   es1->elements->tdata() + ilwr,
+                   (size_t)(iupr - ilwr) * sizeof((*es1->elements)[0]));
+            new(&ue) ArrayLiteralExp(e1->loc, elements);
+            ue.exp()->type = type;
+        }
+    }
+    else
+        new(&ue) CTFEExp(TOKcantexp);
+    assert(ue.exp()->type);
+    return ue;
+}
+
+/* Set a slice of char/integer array literal 'existingAE' from a string 'newval'.
+ * existingAE[firstIndex..firstIndex+newval.length] = newval.
+ */
+void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, size_t firstIndex)
+{
+    size_t newlen =  newval->len;
+    size_t sz = newval->sz;
+    void *s = newval->string;
+    Type *elemType = existingAE->type->nextOf();
+    for (size_t j = 0; j < newlen; j++)
+    {
+        dinteger_t val;
+        switch (sz)
+        {
+            case 1:     val = (( utf8_t *)s)[j];    break;
+            case 2:     val = ((utf16_t *)s)[j];    break;
+            case 4:     val = ((utf32_t *)s)[j];    break;
+            default:    assert(0);                  break;
+        }
+        (*existingAE->elements)[j + firstIndex]
+            = new IntegerExp(newval->loc, val, elemType);
+    }
+}
+
+/* Set a slice of string 'existingSE' from a char array literal 'newae'.
+ *   existingSE[firstIndex..firstIndex+newae.length] = newae.
+ */
+void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, size_t firstIndex)
+{
+    void *s = existingSE->string;
+    for (size_t j = 0; j < newae->elements->dim; j++)
+    {
+        unsigned val = (unsigned)newae->getElement(j)->toInteger();
+        switch (existingSE->sz)
+        {
+            case 1:     (( utf8_t *)s)[j + firstIndex] = ( utf8_t)val;  break;
+            case 2:     ((utf16_t *)s)[j + firstIndex] = (utf16_t)val;  break;
+            case 4:     ((utf32_t *)s)[j + firstIndex] = (utf32_t)val;  break;
+            default:    assert(0);                                      break;
+        }
+    }
+}
+
+/* Set a slice of string 'existingSE' from a string 'newstr'.
+ *   existingSE[firstIndex..firstIndex+newstr.length] = newstr.
+ */
+void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, size_t firstIndex)
+{
+    void *s = existingSE->string;
+    size_t sz = existingSE->sz;
+    assert(sz == newstr->sz);
+    memcpy((char *)s + firstIndex * sz, newstr->string, sz * newstr->len);
+}
+
+/* Compare a string slice with another string slice.
+ * Conceptually equivalent to memcmp( se1[lo1..lo1+len],  se2[lo2..lo2+len])
+ */
+int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len)
+{
+    void *s1 = se1->string;
+    void *s2 = se2->string;
+    size_t sz = se1->sz;
+    assert(sz == se2->sz);
+    return memcmp((char *)s1 + sz * lo1, (char *)s2 + sz * lo2, sz * len);
+}
+
+/* Compare a string slice with an array literal slice
+ * Conceptually equivalent to memcmp( se1[lo1..lo1+len],  ae2[lo2..lo2+len])
+ */
+int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len)
+{
+    void *s = se1->string;
+    size_t sz = se1->sz;
+
+    for (size_t j = 0; j < len; j++)
+    {
+        unsigned val2 = (unsigned)ae2->getElement(j + lo2)->toInteger();
+        unsigned val1;
+        switch (sz)
+        {
+            case 1:     val1 = (( utf8_t *)s)[j + lo1]; break;
+            case 2:     val1 = ((utf16_t *)s)[j + lo1]; break;
+            case 4:     val1 = ((utf32_t *)s)[j + lo1]; break;
+            default:    assert(0);                      break;
+        }
+        int c = val1 - val2;
+        if (c)
+            return c;
+    }
+    return 0;
+}
+
+/* Also return TOKcantexp if this fails
+ */
+UnionExp Cat(Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    Expression *e = CTFEExp::cantexp;
+    Loc loc = e1->loc;
+    Type *t;
+    Type *t1 = e1->type->toBasetype();
+    Type *t2 = e2->type->toBasetype();
+
+    //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+    //printf("\tt1 = %s, t2 = %s, type = %s\n", t1->toChars(), t2->toChars(), type->toChars());
+
+    if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral))
+    {
+        e = e2;
+        t = t1;
+        goto L2;
+    }
+    else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull)
+    {
+        e = e1;
+        t = t2;
+     L2:
+        Type *tn = e->type->toBasetype();
+        if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
+        {
+            // Create a StringExp
+            if (t->nextOf())
+                t = t->nextOf()->toBasetype();
+            unsigned char sz = (unsigned char)t->size();
+
+            dinteger_t v = e->toInteger();
+
+            size_t len = (t->ty == tn->ty) ? 1 : utf_codeLength(sz, (dchar_t)v);
+            void *s = mem.xmalloc((len + 1) * sz);
+            if (t->ty == tn->ty)
+                Port::valcpy(s, v, sz);
+            else
+                utf_encode(sz, s, (dchar_t)v);
+
+            // Add terminating 0
+            memset((char *)s + len * sz, 0, sz);
+
+            new(&ue) StringExp(loc, s, len);
+            StringExp *es = (StringExp *)ue.exp();
+            es->sz = sz;
+            es->committed = 1;
+        }
+        else
+        {
+            // Create an ArrayLiteralExp
+            Expressions *elements = new Expressions();
+            elements->push(e);
+            new(&ue) ArrayLiteralExp(e->loc, elements);
+        }
+        ue.exp()->type = type;
+        assert(ue.exp()->type);
+        return ue;
+    }
+    else if (e1->op == TOKnull && e2->op == TOKnull)
+    {
+        if (type == e1->type)
+        {
+            // Handle null ~= null
+            if (t1->ty == Tarray && t2 == t1->nextOf())
+            {
+                new(&ue) ArrayLiteralExp(e1->loc, e2);
+                ue.exp()->type = type;
+                assert(ue.exp()->type);
+                return ue;
+            }
+            else
+            {
+                new(&ue) UnionExp(e1);
+                assert(ue.exp()->type);
+                return ue;
+            }
+        }
+        if (type == e2->type)
+        {
+            new(&ue) UnionExp(e2);
+            assert(ue.exp()->type);
+            return ue;
+        }
+        new(&ue) NullExp(e1->loc, type);
+        assert(ue.exp()->type);
+        return ue;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKstring)
+    {
+        // Concatenate the strings
+        StringExp *es1 = (StringExp *)e1;
+        StringExp *es2 = (StringExp *)e2;
+        size_t len = es1->len + es2->len;
+        unsigned char sz = es1->sz;
+
+        if (sz != es2->sz)
+        {
+            /* Can happen with:
+             *   auto s = "foo"d ~ "bar"c;
+             */
+            assert(global.errors);
+            new(&ue) CTFEExp(TOKcantexp);
+            assert(ue.exp()->type);
+            return ue;
+        }
+        void *s = mem.xmalloc((len + 1) * sz);
+        memcpy((char *)s, es1->string, es1->len * sz);
+        memcpy((char *)s + es1->len * sz, es2->string, es2->len * sz);
+
+        // Add terminating 0
+        memset((char *)s + len * sz, 0, sz);
+
+        new(&ue) StringExp(loc, s, len);
+        StringExp *es = (StringExp *)ue.exp();
+        es->sz = sz;
+        es->committed = es1->committed | es2->committed;
+        es->type = type;
+        assert(ue.exp()->type);
+        return ue;
+    }
+    else if (e2->op == TOKstring && e1->op == TOKarrayliteral &&
+        t1->nextOf()->isintegral())
+    {
+        // [chars] ~ string --> [chars]
+        StringExp *es = (StringExp *)e2;
+        ArrayLiteralExp *ea = (ArrayLiteralExp *)e1;
+        size_t len = es->len + ea->elements->dim;
+        Expressions * elems = new Expressions;
+        elems->setDim(len);
+        for (size_t i= 0; i < ea->elements->dim; ++i)
+        {
+            (*elems)[i] = ea->getElement(i);
+        }
+        new(&ue) ArrayLiteralExp(e1->loc, elems);
+        ArrayLiteralExp *dest = (ArrayLiteralExp *)ue.exp();
+        dest->type = type;
+        sliceAssignArrayLiteralFromString(dest, es, ea->elements->dim);
+        assert(ue.exp()->type);
+        return ue;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKarrayliteral &&
+        t2->nextOf()->isintegral())
+    {
+        // string ~ [chars] --> [chars]
+        StringExp *es = (StringExp *)e1;
+        ArrayLiteralExp *ea = (ArrayLiteralExp *)e2;
+        size_t len = es->len + ea->elements->dim;
+        Expressions * elems = new Expressions;
+        elems->setDim(len);
+        for (size_t i= 0; i < ea->elements->dim; ++i)
+        {
+            (*elems)[es->len + i] = ea->getElement(i);
+        }
+        new(&ue) ArrayLiteralExp(e1->loc, elems);
+        ArrayLiteralExp *dest = (ArrayLiteralExp *)ue.exp();
+        dest->type = type;
+        sliceAssignArrayLiteralFromString(dest, es, 0);
+        assert(ue.exp()->type);
+        return ue;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKint64)
+    {
+        // string ~ char --> string
+        StringExp *es1 = (StringExp *)e1;
+        StringExp *es;
+        unsigned char sz = es1->sz;
+        dinteger_t v = e2->toInteger();
+
+        // Is it a concatentation of homogenous types?
+        // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar)
+        bool homoConcat = (sz == t2->size());
+        size_t len = es1->len;
+        len += homoConcat ? 1 : utf_codeLength(sz, (dchar_t)v);
+
+        void *s = mem.xmalloc((len + 1) * sz);
+        memcpy(s, es1->string, es1->len * sz);
+        if (homoConcat)
+            Port::valcpy((char *)s + (sz * es1->len), v, sz);
+        else
+            utf_encode(sz, (char *)s + (sz * es1->len), (dchar_t)v);
+
+        // Add terminating 0
+        memset((char *)s + len * sz, 0, sz);
+
+        new(&ue) StringExp(loc, s, len);
+        es = (StringExp *)ue.exp();
+        es->sz = sz;
+        es->committed = es1->committed;
+        es->type = type;
+        assert(ue.exp()->type);
+        return ue;
+    }
+    else if (e1->op == TOKint64 && e2->op == TOKstring)
+    {
+        // Concatenate the strings
+        StringExp *es2 = (StringExp *)e2;
+        size_t len = 1 + es2->len;
+        unsigned char sz = es2->sz;
+        dinteger_t v = e1->toInteger();
+
+        void *s = mem.xmalloc((len + 1) * sz);
+        memcpy((char *)s, &v, sz);
+        memcpy((char *)s + sz, es2->string, es2->len * sz);
+
+        // Add terminating 0
+        memset((char *)s + len * sz, 0, sz);
+
+        new(&ue) StringExp(loc, s, len);
+        StringExp *es = (StringExp *)ue.exp();
+        es->sz = sz;
+        es->committed = es2->committed;
+        es->type = type;
+        assert(ue.exp()->type);
+        return ue;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
+        t1->nextOf()->equals(t2->nextOf()))
+    {
+        // Concatenate the arrays
+        Expressions *elems = ArrayLiteralExp::copyElements(e1, e2);
+
+        new(&ue) ArrayLiteralExp(e1->loc, elems);
+
+        e = ue.exp();
+        if (type->toBasetype()->ty == Tsarray)
+        {
+            e->type = t1->nextOf()->sarrayOf(elems->dim);
+        }
+        else
+            e->type = type;
+        assert(ue.exp()->type);
+        return ue;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKnull &&
+        t1->nextOf()->equals(t2->nextOf()))
+    {
+        e = e1;
+        goto L3;
+    }
+    else if (e1->op == TOKnull && e2->op == TOKarrayliteral &&
+        t1->nextOf()->equals(t2->nextOf()))
+    {
+        e = e2;
+     L3:
+        // Concatenate the array with null
+        Expressions *elems = ArrayLiteralExp::copyElements(e);
+
+        new(&ue) ArrayLiteralExp(e->loc, elems);
+
+        e = ue.exp();
+        if (type->toBasetype()->ty == Tsarray)
+        {
+            e->type = t1->nextOf()->sarrayOf(elems->dim);
+        }
+        else
+            e->type = type;
+        assert(ue.exp()->type);
+        return ue;
+    }
+    else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) &&
+        e1->type->toBasetype()->nextOf() &&
+        e1->type->toBasetype()->nextOf()->equals(e2->type))
+    {
+        Expressions *elems = (e1->op == TOKarrayliteral)
+            ? ArrayLiteralExp::copyElements(e1) : new Expressions();
+        elems->push(e2);
+
+        new(&ue) ArrayLiteralExp(e1->loc, elems);
+
+        e = ue.exp();
+        if (type->toBasetype()->ty == Tsarray)
+        {
+            e->type = e2->type->sarrayOf(elems->dim);
+        }
+        else
+            e->type = type;
+        assert(ue.exp()->type);
+        return ue;
+    }
+    else if (e2->op == TOKarrayliteral &&
+        e2->type->toBasetype()->nextOf()->equals(e1->type))
+    {
+        Expressions *elems = ArrayLiteralExp::copyElements(e1, e2);
+
+        new(&ue) ArrayLiteralExp(e2->loc, elems);
+
+        e = ue.exp();
+        if (type->toBasetype()->ty == Tsarray)
+        {
+            e->type = e1->type->sarrayOf(elems->dim);
+        }
+        else
+            e->type = type;
+        assert(ue.exp()->type);
+        return ue;
+    }
+    else if (e1->op == TOKnull && e2->op == TOKstring)
+    {
+        t = e1->type;
+        e = e2;
+        goto L1;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKnull)
+    {
+        e = e1;
+        t = e2->type;
+      L1:
+        Type *tb = t->toBasetype();
+        if (tb->ty == Tarray && tb->nextOf()->equivalent(e->type))
+        {
+            Expressions *expressions = new Expressions();
+            expressions->push(e);
+            new(&ue) ArrayLiteralExp(loc, expressions);
+            e = ue.exp();
+            e->type = t;
+        }
+        else
+        {
+            new(&ue) UnionExp(e);
+            e = ue.exp();
+        }
+        if (!e->type->equals(type))
+        {
+            StringExp *se = (StringExp *)e->copy();
+            e = se->castTo(NULL, type);
+            new(&ue) UnionExp(e);
+            e = ue.exp();
+        }
+    }
+    else
+        new(&ue) CTFEExp(TOKcantexp);
+    assert(ue.exp()->type);
+    return ue;
+}
+
+UnionExp Ptr(Type *type, Expression *e1)
+{
+    //printf("Ptr(e1 = %s)\n", e1->toChars());
+    UnionExp ue;
+    if (e1->op == TOKadd)
+    {
+        AddExp *ae = (AddExp *)e1;
+        if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
+        {
+            AddrExp *ade = (AddrExp *)ae->e1;
+            if (ade->e1->op == TOKstructliteral)
+            {
+                StructLiteralExp *se = (StructLiteralExp *)ade->e1;
+                unsigned offset = (unsigned)ae->e2->toInteger();
+                Expression *e = se->getField(type, offset);
+                if (e)
+                {
+                    new(&ue) UnionExp(e);
+                    return ue;
+                }
+            }
+        }
+    }
+    new(&ue) CTFEExp(TOKcantexp);
+    return ue;
+}
diff --git a/gcc/d/dfrontend/cppmangle.c b/gcc/d/dfrontend/cppmangle.c
new file mode 100644
index 00000000000..e2eb636affe
--- /dev/null
+++ b/gcc/d/dfrontend/cppmangle.c
@@ -0,0 +1,2001 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/cppmangle.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "mtype.h"
+#include "scope.h"
+#include "init.h"
+#include "expression.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "template.h"
+#include "id.h"
+#include "enum.h"
+#include "import.h"
+#include "aggregate.h"
+#include "target.h"
+
+typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param);
+int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL);
+
+/* Do mangling for C++ linkage.
+ * No attempt is made to support mangling of templates, operator
+ * overloading, or special functions.
+ *
+ * So why don't we use the C++ ABI for D name mangling?
+ * Because D supports a lot of things (like modules) that the C++
+ * ABI has no concept of. These affect every D mangled name,
+ * so nothing would be compatible anyway.
+ */
+
+/*
+ * Follows Itanium C++ ABI 1.86
+ */
+
+class CppMangleVisitor : public Visitor
+{
+    Objects components;
+    OutBuffer buf;
+    bool is_top_level;
+    bool components_on;
+
+    void writeBase36(size_t i)
+    {
+        if (i >= 36)
+        {
+            writeBase36(i / 36);
+            i %= 36;
+        }
+        if (i < 10)
+            buf.writeByte((char)(i + '0'));
+        else if (i < 36)
+            buf.writeByte((char)(i - 10 + 'A'));
+        else
+            assert(0);
+    }
+
+    bool substitute(RootObject *p)
+    {
+        //printf("substitute %s\n", p ? p->toChars() : NULL);
+        if (components_on)
+            for (size_t i = 0; i < components.dim; i++)
+            {
+                //printf("    component[%d] = %s\n", i, components[i] ? components[i]->toChars() : NULL);
+                if (p == components[i])
+                {
+                    //printf("\tmatch\n");
+                    /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ...
+                     */
+                    buf.writeByte('S');
+                    if (i)
+                        writeBase36(i - 1);
+                    buf.writeByte('_');
+                    return true;
+                }
+            }
+        return false;
+    }
+
+    bool exist(RootObject *p)
+    {
+        //printf("exist %s\n", p ? p->toChars() : "NULL");
+        if (components_on)
+            for (size_t i = 0; i < components.dim; i++)
+            {
+                if (p == components[i])
+                {
+                    return true;
+                }
+            }
+        return false;
+    }
+
+    void store(RootObject *p)
+    {
+        //printf("store %s\n", p ? p->toChars() : NULL);
+        if (components_on)
+            components.push(p);
+    }
+
+    void source_name(Dsymbol *s, bool skipname = false)
+    {
+        //printf("source_name(%s)\n", s->toChars());
+        TemplateInstance *ti = s->isTemplateInstance();
+        if (ti)
+        {
+            if (!skipname && !substitute(ti->tempdecl))
+            {
+                store(ti->tempdecl);
+                const char *name = ti->toAlias()->ident->toChars();
+                buf.printf("%d%s", strlen(name), name);
+            }
+            buf.writeByte('I');
+            bool is_var_arg = false;
+            for (size_t i = 0; i < ti->tiargs->dim; i++)
+            {
+                RootObject *o = (RootObject *)(*ti->tiargs)[i];
+
+                TemplateParameter *tp = NULL;
+                TemplateValueParameter *tv = NULL;
+                TemplateTupleParameter *tt = NULL;
+                if (!is_var_arg)
+                {
+                    TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration();
+                    assert(td);
+                    tp = (*td->parameters)[i];
+                    tv = tp->isTemplateValueParameter();
+                    tt = tp->isTemplateTupleParameter();
+                }
+                /*
+                 *           <template-arg> ::= <type>            # type or template
+                 *                          ::= <expr-primary>   # simple expressions
+                 */
+
+                if (tt)
+                {
+                    buf.writeByte('I');
+                    is_var_arg = true;
+                    tp = NULL;
+                }
+
+                if (tv)
+                {
+                    // <expr-primary> ::= L <type> <value number> E                   # integer literal
+                    if (tv->valType->isintegral())
+                    {
+                        Expression *e = isExpression(o);
+                        assert(e);
+                        buf.writeByte('L');
+                        tv->valType->accept(this);
+                        if (tv->valType->isunsigned())
+                        {
+                            buf.printf("%llu", e->toUInteger());
+                        }
+                        else
+                        {
+                            sinteger_t val = e->toInteger();
+                            if (val < 0)
+                            {
+                                val = -val;
+                                buf.writeByte('n');
+                            }
+                            buf.printf("%lld", val);
+                        }
+                        buf.writeByte('E');
+                    }
+                    else
+                    {
+                        s->error("Internal Compiler Error: C++ %s template value parameter is not supported", tv->valType->toChars());
+                        fatal();
+                    }
+                }
+                else if (!tp || tp->isTemplateTypeParameter())
+                {
+                    Type *t = isType(o);
+                    assert(t);
+                    t->accept(this);
+                }
+                else if (tp->isTemplateAliasParameter())
+                {
+                    Dsymbol *d = isDsymbol(o);
+                    Expression *e = isExpression(o);
+                    if (!d && !e)
+                    {
+                        s->error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o->toChars());
+                        fatal();
+                    }
+                    if (d && d->isFuncDeclaration())
+                    {
+                        bool is_nested = d->toParent() && !d->toParent()->isModule() && ((TypeFunction *)d->isFuncDeclaration()->type)->linkage == LINKcpp;
+                        if (is_nested) buf.writeByte('X');
+                        buf.writeByte('L');
+                        mangle_function(d->isFuncDeclaration());
+                        buf.writeByte('E');
+                        if (is_nested) buf.writeByte('E');
+                    }
+                    else if (e && e->op == TOKvar && ((VarExp*)e)->var->isVarDeclaration())
+                    {
+                        VarDeclaration *vd = ((VarExp*)e)->var->isVarDeclaration();
+                        buf.writeByte('L');
+                        mangle_variable(vd, true);
+                        buf.writeByte('E');
+                    }
+                    else if (d && d->isTemplateDeclaration() && d->isTemplateDeclaration()->onemember)
+                    {
+                        if (!substitute(d))
+                        {
+                            cpp_mangle_name(d, false);
+                        }
+                    }
+                    else
+                    {
+                        s->error("Internal Compiler Error: %s is unsupported parameter for C++ template", o->toChars());
+                        fatal();
+                    }
+
+                }
+                else
+                {
+                    s->error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters");
+                    fatal();
+                }
+            }
+            if (is_var_arg)
+            {
+                buf.writeByte('E');
+            }
+            buf.writeByte('E');
+            return;
+        }
+        else
+        {
+            const char *name = s->ident->toChars();
+            buf.printf("%d%s", strlen(name), name);
+        }
+    }
+
+    void prefix_name(Dsymbol *s)
+    {
+        //printf("prefix_name(%s)\n", s->toChars());
+        if (!substitute(s))
+        {
+            Dsymbol *p = s->toParent();
+            if (p && p->isTemplateInstance())
+            {
+                s = p;
+                if (exist(p->isTemplateInstance()->tempdecl))
+                {
+                    p = NULL;
+                }
+                else
+                {
+                    p = p->toParent();
+                }
+            }
+
+            if (p && !p->isModule())
+            {
+                prefix_name(p);
+            }
+            if (!(s->ident == Id::std && is_initial_qualifier(s)))
+                store(s);
+            source_name(s);
+        }
+    }
+
+    /* Is s the initial qualifier?
+     */
+    bool is_initial_qualifier(Dsymbol *s)
+    {
+        Dsymbol *p = s->toParent();
+        if (p && p->isTemplateInstance())
+        {
+            if (exist(p->isTemplateInstance()->tempdecl))
+            {
+                return true;
+            }
+            p = p->toParent();
+        }
+
+        return !p || p->isModule();
+    }
+
+    void cpp_mangle_name(Dsymbol *s, bool qualified)
+    {
+        //printf("cpp_mangle_name(%s, %d)\n", s->toChars(), qualified);
+        Dsymbol *p = s->toParent();
+        Dsymbol *se = s;
+        bool dont_write_prefix = false;
+        if (p && p->isTemplateInstance())
+        {
+            se = p;
+            if (exist(p->isTemplateInstance()->tempdecl))
+                dont_write_prefix = true;
+            p = p->toParent();
+        }
+
+        if (p && !p->isModule())
+        {
+            /* The N..E is not required if:
+             * 1. the parent is 'std'
+             * 2. 'std' is the initial qualifier
+             * 3. there is no CV-qualifier or a ref-qualifier for a member function
+             * ABI 5.1.8
+             */
+            if (p->ident == Id::std &&
+                is_initial_qualifier(p) &&
+                !qualified)
+            {
+                if (s->ident == Id::allocator)
+                {
+                    buf.writestring("Sa");      // "Sa" is short for ::std::allocator
+                    source_name(se, true);
+                }
+                else if (s->ident == Id::basic_string)
+                {
+                    components_on = false;      // turn off substitutions
+                    buf.writestring("Sb");      // "Sb" is short for ::std::basic_string
+                    size_t off = buf.offset;
+                    source_name(se, true);
+                    components_on = true;
+
+                    // Replace ::std::basic_string < char, ::std::char_traits<char>, ::std::allocator<char> >
+                    // with Ss
+                    //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off);
+                    if (buf.offset - off >= 26 &&
+                        memcmp(buf.data + off, "IcSt11char_traitsIcESaIcEE", 26) == 0)
+                    {
+                        buf.remove(off - 2, 28);
+                        buf.insert(off - 2, (const char *)"Ss", 2);
+                        return;
+                    }
+                    buf.setsize(off);
+                    source_name(se, true);
+                }
+                else if (s->ident == Id::basic_istream ||
+                         s->ident == Id::basic_ostream ||
+                         s->ident == Id::basic_iostream)
+                {
+                    /* Replace
+                     * ::std::basic_istream<char,  std::char_traits<char> > with Si
+                     * ::std::basic_ostream<char,  std::char_traits<char> > with So
+                     * ::std::basic_iostream<char, std::char_traits<char> > with Sd
+                     */
+                    size_t off = buf.offset;
+                    components_on = false;      // turn off substitutions
+                    source_name(se, true);
+                    components_on = true;
+
+                    //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off);
+                    if (buf.offset - off >= 21 &&
+                        memcmp(buf.data + off, "IcSt11char_traitsIcEE", 21) == 0)
+                    {
+                        buf.remove(off, 21);
+                        char mbuf[2];
+                        mbuf[0] = 'S';
+                        mbuf[1] = 'i';
+                        if (s->ident == Id::basic_ostream)
+                            mbuf[1] = 'o';
+                        else if(s->ident == Id::basic_iostream)
+                            mbuf[1] = 'd';
+                        buf.insert(off, mbuf, 2);
+                        return;
+                    }
+                    buf.setsize(off);
+                    buf.writestring("St");
+                    source_name(se);
+                }
+                else
+                {
+                    buf.writestring("St");
+                    source_name(se);
+                }
+            }
+            else
+            {
+                buf.writeByte('N');
+                if (!dont_write_prefix)
+                    prefix_name(p);
+                source_name(se);
+                buf.writeByte('E');
+            }
+        }
+        else
+            source_name(se);
+        store(s);
+    }
+
+    void mangle_variable(VarDeclaration *d, bool is_temp_arg_ref)
+    {
+        // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525
+        if (!(d->storage_class & (STCextern | STCfield | STCgshared)))
+        {
+            d->error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported");
+            fatal();
+        }
+
+        Dsymbol *p = d->toParent();
+        if (p && !p->isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE"
+        {
+            buf.writestring("_ZN");
+            prefix_name(p);
+            source_name(d);
+            buf.writeByte('E');
+        }
+        else //char beta[6] should mangle as "beta"
+        {
+            if (!is_temp_arg_ref)
+            {
+                buf.writestring(d->ident->toChars());
+            }
+            else
+            {
+                buf.writestring("_Z");
+                source_name(d);
+            }
+        }
+    }
+
+    void mangle_function(FuncDeclaration *d)
+    {
+        //printf("mangle_function(%s)\n", d->toChars());
+        /*
+         * <mangled-name> ::= _Z <encoding>
+         * <encoding> ::= <function name> <bare-function-type>
+         *         ::= <data name>
+         *         ::= <special-name>
+         */
+        TypeFunction *tf = (TypeFunction *)d->type;
+
+        buf.writestring("_Z");
+        Dsymbol *p = d->toParent();
+        if (p && !p->isModule() && tf->linkage == LINKcpp)
+        {
+            buf.writeByte('N');
+            if (d->type->isConst())
+                buf.writeByte('K');
+            prefix_name(p);
+
+            // See ABI 5.1.8 Compression
+
+            // Replace ::std::allocator with Sa
+            if (buf.offset >= 17 && memcmp(buf.data, "_ZN3std9allocator", 17) == 0)
+            {
+                buf.remove(3, 14);
+                buf.insert(3, (const char *)"Sa", 2);
+            }
+
+            // Replace ::std::basic_string with Sb
+            if (buf.offset >= 21 && memcmp(buf.data, "_ZN3std12basic_string", 21) == 0)
+            {
+                buf.remove(3, 18);
+                buf.insert(3, (const char *)"Sb", 2);
+            }
+
+            // Replace ::std with St
+            if (buf.offset >= 7 && memcmp(buf.data, "_ZN3std", 7) == 0)
+            {
+                buf.remove(3, 4);
+                buf.insert(3, (const char *)"St", 2);
+            }
+            if (buf.offset >= 8 && memcmp(buf.data, "_ZNK3std", 8) == 0)
+            {
+                buf.remove(4, 4);
+                buf.insert(4, (const char *)"St", 2);
+            }
+
+            if (d->isDtorDeclaration())
+            {
+                buf.writestring("D1");
+            }
+            else
+            {
+                source_name(d);
+            }
+            buf.writeByte('E');
+        }
+        else
+        {
+            source_name(d);
+        }
+
+        if (tf->linkage == LINKcpp) //Template args accept extern "C" symbols with special mangling
+        {
+            assert(tf->ty == Tfunction);
+            argsCppMangle(tf->parameters, tf->varargs);
+        }
+    }
+
+    static int paramsCppMangleDg(void *ctx, size_t n, Parameter *fparam)
+    {
+        CppMangleVisitor *mangler = (CppMangleVisitor *)ctx;
+
+        Type *t = fparam->type->merge2();
+        if (fparam->storageClass & (STCout | STCref))
+            t = t->referenceTo();
+        else if (fparam->storageClass & STClazy)
+        {
+            // Mangle as delegate
+            Type *td = new TypeFunction(NULL, t, 0, LINKd);
+            td = new TypeDelegate(td);
+            t = t->merge();
+        }
+#ifdef IN_GCC
+        if (t->ty == Tsarray && Type::tvalist->ty == Tsarray)
+        {
+            // Could be a va_list, which we mangle as a pointer.
+            Type *tb = t->toBasetype()->mutableOf();
+            if (tb == Type::tvalist)
+            {
+                tb = t->nextOf()->pointerTo();
+                t = tb->castMod(t->mod);
+            }
+        }
+#else
+        if (t->ty == Tsarray)
+        {
+            // Mangle static arrays as pointers
+            t->error(Loc(), "Internal Compiler Error: unable to pass static array to extern(C++) function.");
+            t->error(Loc(), "Use pointer instead.");
+            fatal();
+            //t = t->nextOf()->pointerTo();
+        }
+#endif
+
+        /* If it is a basic, enum or struct type,
+         * then don't mark it const
+         */
+        mangler->is_top_level = true;
+        if ((t->ty == Tenum || t->ty == Tstruct || t->ty == Tpointer || t->isTypeBasic()) && t->isConst())
+            t->mutableOf()->accept(mangler);
+        else
+            t->accept(mangler);
+        mangler->is_top_level = false;
+        return 0;
+    }
+
+    void argsCppMangle(Parameters *parameters, int varargs)
+    {
+        if (parameters)
+            Parameter_foreach(parameters, &paramsCppMangleDg, (void*)this);
+
+        if (varargs)
+            buf.writestring("z");
+        else if (!parameters || !parameters->dim)
+            buf.writeByte('v');            // encode ( ) parameters
+    }
+
+public:
+    CppMangleVisitor()
+        : buf(), components(), is_top_level(false), components_on(true)
+    {
+    }
+
+    char *mangleOf(Dsymbol *s)
+    {
+        VarDeclaration *vd = s->isVarDeclaration();
+        FuncDeclaration *fd = s->isFuncDeclaration();
+        if (vd)
+        {
+            mangle_variable(vd, false);
+        }
+        else if (fd)
+        {
+            mangle_function(fd);
+        }
+        else
+        {
+            assert(0);
+        }
+        Target::prefixName(&buf, LINKcpp);
+        return buf.extractString();
+    }
+
+    void visit(Type *t)
+    {
+#ifdef IN_GCC
+        /* Make this the 'vendor extended type' when there is no
+         * C++ analog.
+         * u <source-name>
+         */
+        if (substitute(t))
+            return;
+        assert(t->deco);
+        buf.printf("u%d%s", strlen(t->deco), t->deco);
+        store(t);
+#else
+        if (t->isImmutable() || t->isShared())
+        {
+            t->error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", t->toChars());
+        }
+        else
+        {
+            t->error(Loc(), "Internal Compiler Error: type %s can not be mapped to C++\n", t->toChars());
+        }
+        fatal(); //Fatal, because this error should be handled in frontend
+#endif
+    }
+
+    void visit(TypeBasic *t)
+    {
+        /* ABI spec says:
+         * v        void
+         * w        wchar_t
+         * b        bool
+         * c        char
+         * a        signed char
+         * h        unsigned char
+         * s        short
+         * t        unsigned short
+         * i        int
+         * j        unsigned int
+         * l        long
+         * m        unsigned long
+         * x        long long, __int64
+         * y        unsigned long long, __int64
+         * n        __int128
+         * o        unsigned __int128
+         * f        float
+         * d        double
+         * e        long double, __float80
+         * g        __float128
+         * z        ellipsis
+         * u <source-name>  # vendor extended type
+         */
+
+        char c;
+        char p = 0;
+        switch (t->ty)
+        {
+            case Tvoid:     c = 'v';        break;
+            case Tint8:     c = 'a';        break;
+            case Tuns8:     c = 'h';        break;
+            case Tint16:    c = 's';        break;
+            case Tuns16:    c = 't';        break;
+            case Tint32:    c = 'i';        break;
+            case Tuns32:    c = 'j';        break;
+            case Tfloat32:  c = 'f';        break;
+            case Tint64:    c = (Target::c_longsize == 8 ? 'l' : 'x'); break;
+            case Tuns64:    c = (Target::c_longsize == 8 ? 'm' : 'y'); break;
+            case Tint128:   c = 'n';        break;
+            case Tuns128:   c = 'o';        break;
+            case Tfloat64:  c = 'd';        break;
+            case Tfloat80:  c = 'e';        break;
+            case Tbool:     c = 'b';        break;
+            case Tchar:     c = 'c';        break;
+            case Twchar:    c = 't';        break; // unsigned short
+            case Tdchar:    c = 'w';        break; // wchar_t (UTF-32)
+
+            case Timaginary32: p = 'G'; c = 'f';    break;
+            case Timaginary64: p = 'G'; c = 'd';    break;
+            case Timaginary80: p = 'G'; c = 'e';    break;
+            case Tcomplex32:   p = 'C'; c = 'f';    break;
+            case Tcomplex64:   p = 'C'; c = 'd';    break;
+            case Tcomplex80:   p = 'C'; c = 'e';    break;
+
+            default:        visit((Type *)t); return;
+        }
+        if (t->isImmutable() || t->isShared())
+        {
+            visit((Type *)t);
+        }
+        if (p || t->isConst())
+        {
+            if (substitute(t))
+            {
+                return;
+            }
+            else
+            {
+                store(t);
+            }
+        }
+
+        if (t->isConst())
+            buf.writeByte('K');
+
+        // Handle any target-specific basic types.
+        if (const char *tm = Target::cppTypeMangle(t))
+        {
+            buf.writestring(tm);
+        }
+        else
+        {
+            if (p)
+                buf.writeByte(p);
+            buf.writeByte(c);
+        }
+    }
+
+
+    void visit(TypeVector *t)
+    {
+        is_top_level = false;
+        if (substitute(t))
+            return;
+        store(t);
+        if (t->isImmutable() || t->isShared())
+        {
+            visit((Type *)t);
+        }
+        if (t->isConst())
+            buf.writeByte('K');
+
+        // Handle any target-specific vector types.
+        if (const char *tm = Target::cppTypeMangle(t))
+        {
+            buf.writestring(tm);
+        }
+        else
+        {
+            assert(t->basetype && t->basetype->ty == Tsarray);
+            assert(((TypeSArray *)t->basetype)->dim);
+            //buf.printf("Dv%llu_", ((TypeSArray *)t->basetype)->dim->toInteger());// -- Gnu ABI v.4
+            buf.writestring("U8__vector"); //-- Gnu ABI v.3
+            t->basetype->nextOf()->accept(this);
+        }
+    }
+
+    void visit(TypeSArray *t)
+    {
+        is_top_level = false;
+        if (!substitute(t))
+            store(t);
+        if (t->isImmutable() || t->isShared())
+        {
+            visit((Type *)t);
+        }
+        if (t->isConst())
+            buf.writeByte('K');
+        buf.printf("A%llu_", t->dim ? t->dim->toInteger() : 0);
+        t->next->accept(this);
+    }
+
+    void visit(TypeDArray *t)
+    {
+        visit((Type *)t);
+    }
+
+    void visit(TypeAArray *t)
+    {
+        visit((Type *)t);
+    }
+
+    void visit(TypePointer *t)
+    {
+        is_top_level = false;
+        if (substitute(t))
+            return;
+        if (t->isImmutable() || t->isShared())
+        {
+            visit((Type *)t);
+        }
+        if (t->isConst())
+            buf.writeByte('K');
+        buf.writeByte('P');
+        t->next->accept(this);
+        store(t);
+    }
+
+    void visit(TypeReference *t)
+    {
+        is_top_level = false;
+        if (substitute(t))
+            return;
+        buf.writeByte('R');
+        t->next->accept(this);
+        store(t);
+    }
+
+    void visit(TypeFunction *t)
+    {
+        is_top_level = false;
+        /*
+         *  <function-type> ::= F [Y] <bare-function-type> E
+         *  <bare-function-type> ::= <signature type>+
+         *  # types are possible return type, then parameter types
+         */
+
+        /* ABI says:
+            "The type of a non-static member function is considered to be different,
+            for the purposes of substitution, from the type of a namespace-scope or
+            static member function whose type appears similar. The types of two
+            non-static member functions are considered to be different, for the
+            purposes of substitution, if the functions are members of different
+            classes. In other words, for the purposes of substitution, the class of
+            which the function is a member is considered part of the type of
+            function."
+
+            BUG: Right now, types of functions are never merged, so our simplistic
+            component matcher always finds them to be different.
+            We should use Type::equals on these, and use different
+            TypeFunctions for non-static member functions, and non-static
+            member functions of different classes.
+         */
+        if (substitute(t))
+            return;
+        buf.writeByte('F');
+        if (t->linkage == LINKc)
+            buf.writeByte('Y');
+        Type *tn = t->next;
+        if (t->isref)
+            tn  = tn->referenceTo();
+        tn->accept(this);
+        argsCppMangle(t->parameters, t->varargs);
+        buf.writeByte('E');
+        store(t);
+    }
+
+    void visit(TypeDelegate *t)
+    {
+        visit((Type *)t);
+    }
+
+    void visit(TypeStruct *t)
+    {
+        Identifier *id = t->sym->ident;
+        //printf("struct id = '%s'\n", id->toChars());
+        char c;
+        if (id == Id::__c_long)
+            c = 'l';
+        else if (id == Id::__c_ulong)
+            c = 'm';
+        else
+            c = 0;
+        if (c)
+        {
+            if (t->isImmutable() || t->isShared())
+            {
+                visit((Type *)t);
+            }
+            if (t->isConst())
+            {
+                if (substitute(t))
+                {
+                    return;
+                }
+                else
+                {
+                    store(t);
+                }
+            }
+
+            if (t->isConst())
+                buf.writeByte('K');
+
+            buf.writeByte(c);
+            return;
+        }
+
+        is_top_level = false;
+
+        if (substitute(t))
+            return;
+        if (t->isImmutable() || t->isShared())
+        {
+            visit((Type *)t);
+        }
+        if (t->isConst())
+            buf.writeByte('K');
+
+        // Handle any target-specific struct types.
+        if (const char *tm = Target::cppTypeMangle(t))
+        {
+            buf.writestring(tm);
+        }
+        else
+        {
+            if (!substitute(t->sym))
+            {
+                cpp_mangle_name(t->sym, t->isConst());
+            }
+
+            if (t->isImmutable() || t->isShared())
+            {
+                visit((Type *)t);
+            }
+        }
+
+        if (t->isConst())
+            store(t);
+    }
+
+    void visit(TypeEnum *t)
+    {
+        is_top_level = false;
+        if (substitute(t))
+            return;
+
+        if (t->isConst())
+            buf.writeByte('K');
+
+        if (!substitute(t->sym))
+        {
+            cpp_mangle_name(t->sym, t->isConst());
+        }
+
+        if (t->isImmutable() || t->isShared())
+        {
+            visit((Type *)t);
+        }
+
+        if (t->isConst())
+            store(t);
+    }
+
+    void visit(TypeClass *t)
+    {
+        if (substitute(t))
+            return;
+        if (t->isImmutable() || t->isShared())
+        {
+            visit((Type *)t);
+        }
+        if (t->isConst() && !is_top_level)
+            buf.writeByte('K');
+        is_top_level = false;
+        buf.writeByte('P');
+
+        if (t->isConst())
+            buf.writeByte('K');
+
+        if (!substitute(t->sym))
+        {
+            cpp_mangle_name(t->sym, t->isConst());
+        }
+        if (t->isConst())
+            store(NULL);
+        store(t);
+    }
+
+    const char *mangle_typeinfo(Dsymbol *s)
+    {
+        buf.writestring("_ZTI");
+        cpp_mangle_name(s, false);
+        return buf.extractString();
+    }
+};
+
+const char *toCppMangleItanium(Dsymbol *s)
+{
+    //printf("toCppMangleItanium(%s)\n", s->toChars());
+    CppMangleVisitor v;
+    return v.mangleOf(s);
+}
+
+const char *cppTypeInfoMangleItanium(Dsymbol *s)
+{
+    //printf("cppTypeInfoMangleItanium(%s)\n", s->toChars());
+    CppMangleVisitor v;
+    return v.mangle_typeinfo(s);
+}
+
+// Windows DMC and Microsoft Visual C++ mangling
+#define VC_SAVED_TYPE_CNT 10
+#define VC_SAVED_IDENT_CNT 10
+
+class VisualCPPMangler : public Visitor
+{
+    const char *saved_idents[VC_SAVED_IDENT_CNT];
+    Type *saved_types[VC_SAVED_TYPE_CNT];
+
+    // IS_NOT_TOP_TYPE: when we mangling one argument, we can call visit several times (for base types of arg type)
+    // but we must save only arg type:
+    // For example: if we have an int** argument, we should save "int**" but visit will be called for "int**", "int*", "int"
+    // This flag is set up by the visit(NextType, ) function  and should be reset when the arg type output is finished.
+    // MANGLE_RETURN_TYPE: return type shouldn't be saved and substituted in arguments
+    // IGNORE_CONST: in some cases we should ignore CV-modifiers.
+
+    enum Flags
+    {
+        IS_NOT_TOP_TYPE    = 0x1,
+        MANGLE_RETURN_TYPE = 0x2,
+        IGNORE_CONST       = 0x4,
+        IS_DMC             = 0x8
+    };
+
+    int flags;
+    OutBuffer buf;
+
+    VisualCPPMangler(VisualCPPMangler *rvl)
+        : buf(),
+        flags(0)
+    {
+        flags |= (rvl->flags & IS_DMC);
+        memcpy(&saved_idents, &rvl->saved_idents, sizeof(const char*) * VC_SAVED_IDENT_CNT);
+        memcpy(&saved_types, &rvl->saved_types, sizeof(Type*) * VC_SAVED_TYPE_CNT);
+    }
+public:
+
+    VisualCPPMangler(bool isdmc)
+        : buf(),
+        flags(0)
+    {
+        if (isdmc)
+        {
+            flags |= IS_DMC;
+        }
+        memset(&saved_idents, 0, sizeof(const char*) * VC_SAVED_IDENT_CNT);
+        memset(&saved_types, 0, sizeof(Type*) * VC_SAVED_TYPE_CNT);
+    }
+
+    void visit(Type *type)
+    {
+        if (type->isImmutable() || type->isShared())
+        {
+            type->error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", type->toChars());
+        }
+        else
+        {
+            type->error(Loc(), "Internal Compiler Error: type %s can not be mapped to C++\n", type->toChars());
+        }
+        fatal(); // Fatal, because this error should be handled in frontend
+    }
+
+    void visit(TypeBasic *type)
+    {
+        //printf("visit(TypeBasic); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
+        if (type->isImmutable() || type->isShared())
+        {
+            visit((Type*)type);
+            return;
+        }
+
+        if (type->isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC)))
+        {
+            if (checkTypeSaved(type))
+                return;
+        }
+
+        if ((type->ty == Tbool) && checkTypeSaved(type))// try to replace long name with number
+        {
+            return;
+        }
+        mangleModifier(type);
+        switch (type->ty)
+        {
+            case Tvoid:     buf.writeByte('X');        break;
+            case Tint8:     buf.writeByte('C');        break;
+            case Tuns8:     buf.writeByte('E');        break;
+            case Tint16:    buf.writeByte('F');        break;
+            case Tuns16:    buf.writeByte('G');        break;
+            case Tint32:    buf.writeByte('H');        break;
+            case Tuns32:    buf.writeByte('I');        break;
+            case Tfloat32:  buf.writeByte('M');        break;
+            case Tint64:    buf.writestring("_J");     break;
+            case Tuns64:    buf.writestring("_K");     break;
+            case Tint128:   buf.writestring("_L");     break;
+            case Tuns128:   buf.writestring("_M");     break;
+            case Tfloat64:  buf.writeByte('N');        break;
+            case Tbool:     buf.writestring("_N");     break;
+            case Tchar:     buf.writeByte('D');        break;
+            case Tdchar:    buf.writeByte('I');        break; // unsigned int
+
+            case Tfloat80:
+                if (flags & IS_DMC)
+                    buf.writestring("_Z"); // DigitalMars long double
+                else
+                    buf.writestring("_T"); // Intel long double
+                break;
+
+            case Twchar:
+                if (flags & IS_DMC)
+                    buf.writestring("_Y"); // DigitalMars wchar_t
+                else
+                    buf.writestring("_W"); // Visual C++ wchar_t
+                break;
+
+            default:        visit((Type*)type); return;
+        }
+        flags &= ~IS_NOT_TOP_TYPE;
+        flags &= ~IGNORE_CONST;
+    }
+
+    void visit(TypeVector *type)
+    {
+        //printf("visit(TypeVector); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
+        if (checkTypeSaved(type))
+            return;
+        buf.writestring("T__m128@@"); // may be better as __m128i or __m128d?
+        flags &= ~IS_NOT_TOP_TYPE;
+        flags &= ~IGNORE_CONST;
+    }
+
+    void visit(TypeSArray *type)
+    {
+        // This method can be called only for static variable type mangling.
+        //printf("visit(TypeSArray); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
+        if (checkTypeSaved(type))
+            return;
+        // first dimension always mangled as const pointer
+        if (flags & IS_DMC)
+            buf.writeByte('Q');
+        else
+            buf.writeByte('P');
+
+        flags |= IS_NOT_TOP_TYPE;
+        assert(type->next);
+        if (type->next->ty == Tsarray)
+        {
+            mangleArray((TypeSArray*)type->next);
+        }
+        else
+        {
+            type->next->accept(this);
+        }
+    }
+
+    // attention: D int[1][2]* arr mapped to C++ int arr[][2][1]; (because it's more typical situation)
+    // There is not way to map int C++ (*arr)[2][1] to D
+    void visit(TypePointer *type)
+    {
+        //printf("visit(TypePointer); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
+        if (type->isImmutable() || type->isShared())
+        {
+            visit((Type*)type);
+            return;
+        }
+
+        assert(type->next);
+        if (type->next->ty == Tfunction)
+        {
+            const char *arg = mangleFunctionType((TypeFunction*)type->next); // compute args before checking to save; args should be saved before function type
+
+            // If we've mangled this function early, previous call is meaningless.
+            // However we should do it before checking to save types of function arguments before function type saving.
+            // If this function was already mangled, types of all it arguments are save too, thus previous can't save
+            // anything if function is saved.
+            if (checkTypeSaved(type))
+                return;
+
+            if (type->isConst())
+                buf.writeByte('Q'); // const
+            else
+                buf.writeByte('P'); // mutable
+
+            buf.writeByte('6'); // pointer to a function
+            buf.writestring(arg);
+            flags &= ~IS_NOT_TOP_TYPE;
+            flags &= ~IGNORE_CONST;
+            return;
+        }
+        else if (type->next->ty == Tsarray)
+        {
+            if (checkTypeSaved(type))
+                return;
+            mangleModifier(type);
+
+            if (type->isConst() || !(flags & IS_DMC))
+                buf.writeByte('Q'); // const
+            else
+                buf.writeByte('P'); // mutable
+
+            if (global.params.is64bit)
+                buf.writeByte('E');
+            flags |= IS_NOT_TOP_TYPE;
+
+            mangleArray((TypeSArray*)type->next);
+            return;
+        }
+        else
+        {
+            if (checkTypeSaved(type))
+                return;
+            mangleModifier(type);
+
+            if (type->isConst())
+            {
+                buf.writeByte('Q'); // const
+            }
+            else
+            {
+                buf.writeByte('P'); // mutable
+            }
+
+            if (global.params.is64bit)
+                buf.writeByte('E');
+            flags |= IS_NOT_TOP_TYPE;
+            type->next->accept(this);
+        }
+    }
+
+    void visit(TypeReference *type)
+    {
+        //printf("visit(TypeReference); type = %s\n", type->toChars());
+        if (checkTypeSaved(type))
+            return;
+
+        if (type->isImmutable() || type->isShared())
+        {
+            visit((Type*)type);
+            return;
+        }
+
+        buf.writeByte('A'); // mutable
+
+        if (global.params.is64bit)
+            buf.writeByte('E');
+        flags |= IS_NOT_TOP_TYPE;
+        assert(type->next);
+        if (type->next->ty == Tsarray)
+        {
+            mangleArray((TypeSArray*)type->next);
+        }
+        else
+        {
+            type->next->accept(this);
+        }
+    }
+
+    void visit(TypeFunction *type)
+    {
+        const char *arg = mangleFunctionType(type);
+
+        if ((flags & IS_DMC))
+        {
+            if (checkTypeSaved(type))
+                return;
+        }
+        else
+        {
+            buf.writestring("$$A6");
+        }
+        buf.writestring(arg);
+        flags &= ~(IS_NOT_TOP_TYPE | IGNORE_CONST);
+    }
+
+    void visit(TypeStruct *type)
+    {
+        Identifier *id = type->sym->ident;
+        char c;
+        if (id == Id::__c_long_double)
+            c = 'O';                    // VC++ long double
+        else if (id == Id::__c_long)
+            c = 'J';                    // VC++ long
+        else if (id == Id::__c_ulong)
+            c = 'K';                    // VC++ unsigned long
+        else
+            c = 0;
+
+        if (c)
+        {
+            if (type->isImmutable() || type->isShared())
+            {
+                visit((Type*)type);
+                return;
+            }
+
+            if (type->isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC)))
+            {
+                if (checkTypeSaved(type))
+                    return;
+            }
+
+            mangleModifier(type);
+            buf.writeByte(c);
+        }
+        else
+        {
+            if (checkTypeSaved(type))
+                return;
+            //printf("visit(TypeStruct); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
+            mangleModifier(type);
+            if (type->sym->isUnionDeclaration())
+                buf.writeByte('T');
+            else
+                buf.writeByte(type->cppmangle == CPPMANGLEclass ? 'V' : 'U');
+            mangleIdent(type->sym);
+        }
+        flags &= ~IS_NOT_TOP_TYPE;
+        flags &= ~IGNORE_CONST;
+    }
+
+    void visit(TypeEnum *type)
+    {
+        //printf("visit(TypeEnum); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
+        if (checkTypeSaved(type))
+            return;
+        mangleModifier(type);
+        buf.writeByte('W');
+
+        switch (type->sym->memtype->ty)
+        {
+            case Tchar:
+            case Tint8:
+                buf.writeByte('0');
+                break;
+            case Tuns8:
+                buf.writeByte('1');
+                break;
+            case Tint16:
+                buf.writeByte('2');
+                break;
+            case Tuns16:
+                buf.writeByte('3');
+                break;
+            case Tint32:
+                buf.writeByte('4');
+                break;
+            case Tuns32:
+                buf.writeByte('5');
+                break;
+            case Tint64:
+                buf.writeByte('6');
+                break;
+            case Tuns64:
+                buf.writeByte('7');
+                break;
+            default:
+                visit((Type*)type);
+                break;
+        }
+
+        mangleIdent(type->sym);
+        flags &= ~IS_NOT_TOP_TYPE;
+        flags &= ~IGNORE_CONST;
+    }
+
+    // D class mangled as pointer to C++ class
+    // const(Object) mangled as Object const* const
+    void visit(TypeClass *type)
+    {
+        //printf("visit(TypeClass); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE));
+        if (checkTypeSaved(type))
+            return;
+        if (flags & IS_NOT_TOP_TYPE)
+            mangleModifier(type);
+
+        if (type->isConst())
+            buf.writeByte('Q');
+        else
+            buf.writeByte('P');
+
+        if (global.params.is64bit)
+            buf.writeByte('E');
+
+        flags |= IS_NOT_TOP_TYPE;
+        mangleModifier(type);
+
+        buf.writeByte(type->cppmangle == CPPMANGLEstruct ? 'U' : 'V');
+
+        mangleIdent(type->sym);
+        flags &= ~IS_NOT_TOP_TYPE;
+        flags &= ~IGNORE_CONST;
+    }
+
+    char *mangleOf(Dsymbol *s)
+    {
+        VarDeclaration *vd = s->isVarDeclaration();
+        FuncDeclaration *fd = s->isFuncDeclaration();
+        if (vd)
+        {
+            mangleVariable(vd);
+        }
+        else if (fd)
+        {
+            mangleFunction(fd);
+        }
+        else
+        {
+            assert(0);
+        }
+        return buf.extractString();
+    }
+private:
+
+    void mangleFunction(FuncDeclaration *d)
+    {
+        // <function mangle> ? <qualified name> <flags> <return type> <arg list>
+        assert(d);
+        buf.writeByte('?');
+        mangleIdent(d);
+
+        if (d->needThis()) // <flags> ::= <virtual/protection flag> <const/volatile flag> <calling convention flag>
+        {
+            // Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++
+            //printf("%s: isVirtualMethod = %d, isVirtual = %d, vtblIndex = %d, interfaceVirtual = %p\n",
+                //d->toChars(), d->isVirtualMethod(), d->isVirtual(), (int)d->vtblIndex, d->interfaceVirtual);
+            if (d->isVirtual() && (d->vtblIndex != -1 || d->interfaceVirtual || d->overrideInterface()))
+            {
+                switch (d->protection.kind)
+                {
+                    case PROTprivate:
+                        buf.writeByte('E');
+                        break;
+                    case PROTprotected:
+                        buf.writeByte('M');
+                        break;
+                    default:
+                        buf.writeByte('U');
+                        break;
+                }
+            }
+            else
+            {
+                switch (d->protection.kind)
+                {
+                    case PROTprivate:
+                        buf.writeByte('A');
+                        break;
+                    case PROTprotected:
+                        buf.writeByte('I');
+                        break;
+                    default:
+                        buf.writeByte('Q');
+                        break;
+                }
+            }
+            if (global.params.is64bit)
+                buf.writeByte('E');
+            if (d->type->isConst())
+            {
+                buf.writeByte('B');
+            }
+            else
+            {
+                buf.writeByte('A');
+            }
+        }
+        else if (d->isMember2()) // static function
+        {                        // <flags> ::= <virtual/protection flag> <calling convention flag>
+            switch (d->protection.kind)
+            {
+                case PROTprivate:
+                    buf.writeByte('C');
+                    break;
+                case PROTprotected:
+                    buf.writeByte('K');
+                    break;
+                default:
+                    buf.writeByte('S');
+                    break;
+            }
+        }
+        else // top-level function
+        {    // <flags> ::= Y <calling convention flag>
+            buf.writeByte('Y');
+        }
+
+        const char *args = mangleFunctionType((TypeFunction *)d->type, (bool)d->needThis(), d->isCtorDeclaration() || d->isDtorDeclaration());
+        buf.writestring(args);
+    }
+
+    void mangleVariable(VarDeclaration *d)
+    {
+        // <static variable mangle> ::= ? <qualified name> <protection flag> <const/volatile flag> <type>
+        assert(d);
+        // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525
+        if (!(d->storage_class & (STCextern | STCfield | STCgshared)))
+        {
+            d->error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported");
+            fatal();
+        }
+        buf.writeByte('?');
+        mangleIdent(d);
+
+        assert((d->storage_class & STCfield) || !d->needThis());
+
+        if (d->parent && d->parent->isModule()) // static member
+        {
+            buf.writeByte('3');
+        }
+        else
+        {
+            switch (d->protection.kind)
+            {
+                case PROTprivate:
+                    buf.writeByte('0');
+                    break;
+                case PROTprotected:
+                    buf.writeByte('1');
+                    break;
+                default:
+                    buf.writeByte('2');
+                    break;
+            }
+        }
+
+        char cv_mod = 0;
+        Type *t = d->type;
+
+        if (t->isImmutable() || t->isShared())
+        {
+            visit((Type*)t);
+            return;
+        }
+        if (t->isConst())
+        {
+            cv_mod = 'B'; // const
+        }
+        else
+        {
+            cv_mod = 'A'; // mutable
+        }
+
+        if (t->ty != Tpointer)
+            t = t->mutableOf();
+
+        t->accept(this);
+
+        if ((t->ty == Tpointer || t->ty == Treference || t->ty == Tclass) && global.params.is64bit)
+        {
+            buf.writeByte('E');
+        }
+
+        buf.writeByte(cv_mod);
+    }
+
+    void mangleName(Dsymbol *sym, bool dont_use_back_reference = false)
+    {
+        //printf("mangleName('%s')\n", sym->toChars());
+        const char *name = NULL;
+        bool is_dmc_template = false;
+        if (sym->isDtorDeclaration())
+        {
+            buf.writestring("?1");
+            return;
+        }
+        if (TemplateInstance *ti = sym->isTemplateInstance())
+        {
+            VisualCPPMangler tmp((flags & IS_DMC) ? true : false);
+            tmp.buf.writeByte('?');
+            tmp.buf.writeByte('$');
+            tmp.buf.writestring(ti->name->toChars());
+            tmp.saved_idents[0] = ti->name->toChars();
+            tmp.buf.writeByte('@');
+            if (flags & IS_DMC)
+            {
+                tmp.mangleIdent(sym->parent, true);
+                is_dmc_template = true;
+            }
+
+            bool is_var_arg = false;
+            for (size_t i = 0; i < ti->tiargs->dim; i++)
+            {
+                RootObject *o = (*ti->tiargs)[i];
+
+                TemplateParameter *tp = NULL;
+                TemplateValueParameter *tv = NULL;
+                TemplateTupleParameter *tt = NULL;
+                if (!is_var_arg)
+                {
+                    TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration();
+                    assert(td);
+                    tp = (*td->parameters)[i];
+                    tv = tp->isTemplateValueParameter();
+                    tt = tp->isTemplateTupleParameter();
+                }
+
+                if (tt)
+                {
+                    is_var_arg = true;
+                    tp = NULL;
+                }
+                if (tv)
+                {
+                    if (tv->valType->isintegral())
+                    {
+
+                        tmp.buf.writeByte('$');
+                        tmp.buf.writeByte('0');
+
+                        Expression *e = isExpression(o);
+                        assert(e);
+
+                        if (tv->valType->isunsigned())
+                        {
+                            tmp.mangleNumber(e->toUInteger());
+                        }
+                        else if(is_dmc_template)
+                        {
+                            // NOTE: DMC mangles everything based on
+                            // unsigned int
+                            tmp.mangleNumber(e->toInteger());
+                        }
+                        else
+                        {
+                            sinteger_t val = e->toInteger();
+                            if (val < 0)
+                            {
+                                val = -val;
+                                tmp.buf.writeByte('?');
+                            }
+                            tmp.mangleNumber(val);
+                        }
+                    }
+                    else
+                    {
+                        sym->error("Internal Compiler Error: C++ %s template value parameter is not supported", tv->valType->toChars());
+                        fatal();
+                    }
+                }
+                else if (!tp || tp->isTemplateTypeParameter())
+                {
+                    Type *t = isType(o);
+                    assert(t);
+                    t->accept(&tmp);
+                }
+                else if (tp->isTemplateAliasParameter())
+                {
+                    Dsymbol *d = isDsymbol(o);
+                    Expression *e = isExpression(o);
+                    if (!d && !e)
+                    {
+                        sym->error("Internal Compiler Error: %s is unsupported parameter for C++ template", o->toChars());
+                        fatal();
+                    }
+                    if (d && d->isFuncDeclaration())
+                    {
+                        tmp.buf.writeByte('$');
+                        tmp.buf.writeByte('1');
+                        tmp.mangleFunction(d->isFuncDeclaration());
+                    }
+                    else if (e && e->op == TOKvar && ((VarExp*)e)->var->isVarDeclaration())
+                    {
+                        tmp.buf.writeByte('$');
+                        if (flags & IS_DMC)
+                            tmp.buf.writeByte('1');
+                        else
+                            tmp.buf.writeByte('E');
+                        tmp.mangleVariable(((VarExp*)e)->var->isVarDeclaration());
+                    }
+                    else if (d && d->isTemplateDeclaration() && d->isTemplateDeclaration()->onemember)
+                    {
+
+                        Dsymbol *ds = d->isTemplateDeclaration()->onemember;
+                        if (flags & IS_DMC)
+                        {
+                            tmp.buf.writeByte('V');
+                        }
+                        else
+                        {
+                            if (ds->isUnionDeclaration())
+                            {
+                                tmp.buf.writeByte('T');
+                            }
+                            else if (ds->isStructDeclaration())
+                            {
+                                tmp.buf.writeByte('U');
+                            }
+                            else if (ds->isClassDeclaration())
+                            {
+                                tmp.buf.writeByte('V');
+                            }
+                            else
+                            {
+                                sym->error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters");
+                                fatal();
+                            }
+                        }
+                        tmp.mangleIdent(d);
+                    }
+                    else
+                    {
+                        sym->error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o->toChars());
+                        fatal();
+                    }
+
+                }
+                else
+                {
+                    sym->error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters");
+                    fatal();
+                }
+            }
+            name = tmp.buf.extractString();
+        }
+        else
+        {
+            name = sym->ident->toChars();
+        }
+        assert(name);
+        if (is_dmc_template)
+        {
+            if (checkAndSaveIdent(name))
+                return;
+        }
+        else
+        {
+            if (dont_use_back_reference)
+            {
+                saveIdent(name);
+            }
+            else
+            {
+                if (checkAndSaveIdent(name))
+                    return;
+            }
+        }
+        buf.writestring(name);
+        buf.writeByte('@');
+    }
+
+    // returns true if name already saved
+    bool checkAndSaveIdent(const char *name)
+    {
+        for (size_t i = 0; i < VC_SAVED_IDENT_CNT; i++)
+        {
+            if (!saved_idents[i]) // no saved same name
+            {
+                saved_idents[i] = name;
+                break;
+            }
+
+            if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name
+            {
+                buf.writeByte(i + '0');
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void saveIdent(const char *name)
+    {
+        for (size_t i = 0; i < VC_SAVED_IDENT_CNT; i++)
+        {
+            if (!saved_idents[i]) // no saved same name
+            {
+                saved_idents[i] = name;
+                break;
+            }
+
+            if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name
+            {
+                return;
+            }
+        }
+    }
+
+    void mangleIdent(Dsymbol *sym, bool dont_use_back_reference = false)
+    {
+        // <qualified name> ::= <sub-name list> @
+        // <sub-name list>  ::= <sub-name> <name parts>
+        //                  ::= <sub-name>
+
+        // <sub-name> ::= <identifier> @
+        //            ::= ?$ <identifier> @ <template args> @
+        //            :: <back reference>
+
+        // <back reference> ::= 0-9
+
+        // <template args> ::= <template arg> <template args>
+        //                ::= <template arg>
+
+        // <template arg>  ::= <type>
+        //                ::= $0<encoded integral number>
+
+        //printf("mangleIdent('%s')\n", sym->toChars());
+        Dsymbol *p = sym;
+        if (p->toParent() && p->toParent()->isTemplateInstance())
+        {
+            p = p->toParent();
+        }
+        while (p && !p->isModule())
+        {
+            mangleName(p, dont_use_back_reference);
+
+            p = p->toParent();
+            if (p->toParent() && p->toParent()->isTemplateInstance())
+            {
+                p = p->toParent();
+            }
+        }
+        if (!dont_use_back_reference)
+            buf.writeByte('@');
+    }
+
+    void mangleNumber(dinteger_t num)
+    {
+        if (!num) // 0 encoded as "A@"
+        {
+            buf.writeByte('A');
+            buf.writeByte('@');
+            return;
+        }
+        if (num <= 10) // 5 encoded as "4"
+        {
+            buf.writeByte((char)(num - 1 + '0'));
+            return;
+        }
+
+        char buff[17];
+        buff[16] = 0;
+        size_t i = 16;
+        while (num)
+        {
+            --i;
+            buff[i] = num % 16 + 'A';
+            num /=16;
+        }
+        buf.writestring(&buff[i]);
+        buf.writeByte('@');
+    }
+
+    bool checkTypeSaved(Type *type)
+    {
+        if (flags & IS_NOT_TOP_TYPE)
+            return false;
+        if (flags & MANGLE_RETURN_TYPE)
+            return false;
+        for (size_t i = 0; i < VC_SAVED_TYPE_CNT; i++)
+        {
+            if (!saved_types[i]) // no saved same type
+            {
+                saved_types[i] = type;
+                return false;
+            }
+            if (saved_types[i]->equals(type)) // ok, we've found same type. use index instead of type
+            {
+                buf.writeByte(i + '0');
+                flags &= ~IS_NOT_TOP_TYPE;
+                flags &= ~IGNORE_CONST;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void mangleModifier(Type *type)
+    {
+        if (flags & IGNORE_CONST)
+            return;
+        if (type->isImmutable() || type->isShared())
+        {
+            visit((Type*)type);
+            return;
+        }
+        if (type->isConst())
+        {
+            if (flags & IS_NOT_TOP_TYPE)
+                buf.writeByte('B'); // const
+                else if ((flags & IS_DMC) && type->ty != Tpointer)
+                    buf.writestring("_O");
+        }
+        else if (flags & IS_NOT_TOP_TYPE)
+            buf.writeByte('A'); // mutable
+    }
+
+    void mangleArray(TypeSArray *type)
+    {
+        mangleModifier(type);
+        size_t i=0;
+        Type *cur = type;
+        while (cur && cur->ty == Tsarray)
+        {
+            i++;
+            cur = cur->nextOf();
+        }
+        buf.writeByte('Y');
+        mangleNumber(i); // count of dimensions
+        cur = type;
+        while (cur && cur->ty == Tsarray) // sizes of dimensions
+        {
+            TypeSArray *sa = (TypeSArray*)cur;
+            mangleNumber(sa->dim ? sa->dim->toInteger() : 0);
+            cur = cur->nextOf();
+        }
+        flags |= IGNORE_CONST;
+        cur->accept(this);
+    }
+
+    static int mangleParameterDg(void *ctx, size_t n, Parameter *p)
+    {
+        VisualCPPMangler *mangler = (VisualCPPMangler *)ctx;
+
+        Type *t = p->type;
+        if (p->storageClass & (STCout | STCref))
+        {
+            t = t->referenceTo();
+        }
+        else if (p->storageClass & STClazy)
+        {
+            // Mangle as delegate
+            Type *td = new TypeFunction(NULL, t, 0, LINKd);
+            td = new TypeDelegate(td);
+            t = t->merge();
+        }
+        if (t->ty == Tsarray)
+        {
+            t->error(Loc(), "Internal Compiler Error: unable to pass static array to extern(C++) function.");
+            t->error(Loc(), "Use pointer instead.");
+            fatal();
+        }
+        mangler->flags &= ~IS_NOT_TOP_TYPE;
+        mangler->flags &= ~IGNORE_CONST;
+        t->accept(mangler);
+
+        return 0;
+    }
+
+    const char *mangleFunctionType(TypeFunction *type, bool needthis = false, bool noreturn = false)
+    {
+        VisualCPPMangler tmp(this);
+        // Calling convention
+        if (global.params.is64bit) // always Microsoft x64 calling convention
+        {
+            tmp.buf.writeByte('A');
+        }
+        else
+        {
+            switch (type->linkage)
+            {
+                case LINKc:
+                    tmp.buf.writeByte('A');
+                    break;
+                case LINKcpp:
+                    if (needthis && type->varargs != 1)
+                        tmp.buf.writeByte('E'); // thiscall
+                    else
+                        tmp.buf.writeByte('A'); // cdecl
+                    break;
+                case LINKwindows:
+                    tmp.buf.writeByte('G'); // stdcall
+                    break;
+                case LINKpascal:
+                    tmp.buf.writeByte('C');
+                    break;
+                default:
+                    tmp.visit((Type*)type);
+                    break;
+            }
+        }
+
+        tmp.flags &= ~IS_NOT_TOP_TYPE;
+        if (noreturn)
+        {
+            tmp.buf.writeByte('@');
+        }
+        else
+        {
+            Type *rettype = type->next;
+            if (type->isref)
+                rettype = rettype->referenceTo();
+            flags &= ~IGNORE_CONST;
+            if (rettype->ty == Tstruct || rettype->ty == Tenum)
+            {
+                Identifier *id = rettype->toDsymbol(NULL)->ident;
+                if (id != Id::__c_long_double &&
+                    id != Id::__c_long &&
+                    id != Id::__c_ulong)
+                {
+                    tmp.buf.writeByte('?');
+                    tmp.buf.writeByte('A');
+                }
+            }
+            tmp.flags |= MANGLE_RETURN_TYPE;
+            rettype->accept(&tmp);
+            tmp.flags &= ~MANGLE_RETURN_TYPE;
+        }
+        if (!type->parameters || !type->parameters->dim)
+        {
+            if (type->varargs == 1)
+                tmp.buf.writeByte('Z');
+            else
+                tmp.buf.writeByte('X');
+        }
+        else
+        {
+            Parameter_foreach(type->parameters, &mangleParameterDg, (void*)&tmp);
+            if (type->varargs == 1)
+            {
+                tmp.buf.writeByte('Z');
+            }
+            else
+            {
+                tmp.buf.writeByte('@');
+            }
+        }
+
+        tmp.buf.writeByte('Z');
+        const char *ret = tmp.buf.extractString();
+        memcpy(&saved_idents, &tmp.saved_idents, sizeof(const char*) * VC_SAVED_IDENT_CNT);
+        memcpy(&saved_types, &tmp.saved_types, sizeof(Type*) * VC_SAVED_TYPE_CNT);
+        return ret;
+    }
+};
+
+const char *toCppMangleMSVC(Dsymbol *s)
+{
+    VisualCPPMangler v(!global.params.mscoff);
+    return v.mangleOf(s);
+}
+
+const char *cppTypeInfoMangleMSVC(Dsymbol *s)
+{
+    //printf("cppTypeInfoMangleMSVC(%s)\n", s->toChars());
+    assert(0);
+}
diff --git a/gcc/d/dfrontend/ctfe.h b/gcc/d/dfrontend/ctfe.h
new file mode 100644
index 00000000000..28e6f950370
--- /dev/null
+++ b/gcc/d/dfrontend/ctfe.h
@@ -0,0 +1,279 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/ctfe.h
+ */
+
+#ifndef DMD_CTFE_H
+#define DMD_CTFE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "arraytypes.h"
+#include "tokens.h"
+#include "expression.h"
+
+/**
+   Global status of the CTFE engine. Mostly used for performance diagnostics
+ */
+struct CtfeStatus
+{
+    static int callDepth; // current number of recursive calls
+    /* When printing a stack trace,
+     * suppress this number of calls
+     */
+    static int stackTraceCallsToSuppress;
+    static int maxCallDepth; // highest number of recursive calls
+    static int numArrayAllocs; // Number of allocated arrays
+    static int numAssignments; // total number of assignments executed
+};
+
+/**
+  A reference to a class, or an interface. We need this when we
+  point to a base class (we must record what the type is).
+ */
+class ClassReferenceExp : public Expression
+{
+public:
+    StructLiteralExp *value;
+    ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type);
+    ClassDeclaration *originalClass();
+
+    /// Return index of the field, or -1 if not found
+    int getFieldIndex(Type *fieldtype, unsigned fieldoffset);
+    /// Return index of the field, or -1 if not found
+    /// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
+    int findFieldIndexByName(VarDeclaration *v);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// The various functions are used only to detect compiler CTFE bugs
+Expression *getValue(VarDeclaration *vd);
+bool hasValue(VarDeclaration *vd);
+void setValueNull(VarDeclaration *vd);
+void setValueWithoutChecking(VarDeclaration *vd, Expression *newval);
+void setValue(VarDeclaration *vd, Expression *newval);
+
+/// Return index of the field, or -1 if not found
+/// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
+int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v);
+
+
+/** An uninitialized value
+ */
+class VoidInitExp : public Expression
+{
+public:
+    VarDeclaration *var;
+
+    VoidInitExp(VarDeclaration *var, Type *type);
+    const char *toChars();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// Create an appropriate void initializer
+UnionExp voidInitLiteral(Type *t, VarDeclaration *var);
+
+/** Fake class which holds the thrown exception.
+    Used for implementing exception handling.
+*/
+class ThrownExceptionExp : public Expression
+{
+public:
+    ClassReferenceExp *thrown; // the thing being tossed
+    ThrownExceptionExp(Loc loc, ClassReferenceExp *victim);
+    const char *toChars();
+    /// Generate an error message when this exception is not caught
+    void generateUncaughtError();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+// This type is only used by the interpreter.
+
+class CTFEExp : public Expression
+{
+public:
+    CTFEExp(TOK tok);
+
+    const char *toChars();
+
+    // Handy instances to share
+    static CTFEExp *cantexp;
+    static CTFEExp *voidexp;
+    static CTFEExp *breakexp;
+    static CTFEExp *continueexp;
+    static CTFEExp *gotoexp;
+
+    static bool isCantExp(Expression *e) { return e && e->op == TOKcantexp; }
+    static bool isGotoExp(Expression *e) { return e && e->op == TOKgoto; }
+};
+
+/****************************************************************/
+
+
+/// True if 'e' is TOKcantexp, or an exception
+bool exceptionOrCantInterpret(Expression *e);
+
+// Used for debugging only
+void showCtfeExpr(Expression *e, int level = 0);
+
+/// Return true if this is a valid CTFE expression
+bool isCtfeValueValid(Expression *newval);
+bool isCtfeReferenceValid(Expression *newval);
+
+/// Given expr, which evaluates to an array/AA/string literal,
+/// return true if it needs to be copied
+bool needToCopyLiteral(Expression *expr);
+
+/// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
+/// This value will be used for in-place modification.
+UnionExp copyLiteral(Expression *e);
+
+/// Set this literal to the given type, copying it if necessary
+Expression *paintTypeOntoLiteral(Type *type, Expression *lit);
+UnionExp paintTypeOntoLiteralCopy(Type *type, Expression *lit);
+
+/// Convert from a CTFE-internal slice, into a normal Expression
+Expression *resolveSlice(Expression *e);
+
+/// Determine the array length, without interpreting the expression.
+uinteger_t resolveArrayLength(Expression *e);
+
+/// Create an array literal consisting of 'elem' duplicated 'dim' times.
+ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type,
+        Expression *elem, size_t dim);
+
+/// Create a string literal consisting of 'value' duplicated 'dim' times.
+StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type,
+        unsigned value, size_t dim, unsigned char sz);
+
+
+/* Set dest = src, where both dest and src are container value literals
+ * (ie, struct literals, or static arrays (can be an array literal or a string)
+ * Assignment is recursively in-place.
+ * Purpose: any reference to a member of 'dest' will remain valid after the
+ * assignment.
+ */
+void assignInPlace(Expression *dest, Expression *src);
+
+/// Duplicate the elements array, then set field 'indexToChange' = newelem.
+Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem);
+
+/// Create a new struct literal, which is the same as se except that se.field[offset] = elem
+Expression * modifyStructField(Type *type, StructLiteralExp *se, size_t offset, Expression *newval);
+
+/// Given an AA literal aae,  set arr[index] = newval and return the new array.
+Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae,
+    Expression *index, Expression *newval);
+
+/// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
+/// oldlen, change its length to newlen. If the newlen is longer than oldlen,
+/// all new elements will be set to the default initializer for the element type.
+UnionExp changeArrayLiteralLength(Loc loc, TypeArray *arrayType,
+    Expression *oldval,  size_t oldlen, size_t newlen);
+
+
+
+/// Return true if t is a pointer (not a function pointer)
+bool isPointer(Type *t);
+
+// For CTFE only. Returns true if 'e' is TRUE or a non-null pointer.
+bool isTrueBool(Expression *e);
+
+/// Is it safe to convert from srcPointee* to destPointee* ?
+///  srcPointee is the genuine type (never void).
+///  destPointee may be void.
+bool isSafePointerCast(Type *srcPointee, Type *destPointee);
+
+/// Given pointer e, return the memory block expression it points to,
+/// and set ofs to the offset within that memory block.
+Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs);
+
+/// Return true if agg1 and agg2 are pointers to the same memory block
+bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2);
+
+// return e1 - e2 as an integer, or error if not possible
+UnionExp pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2);
+
+/// Return 1 if true, 0 if false
+/// -1 if comparison is illegal because they point to non-comparable memory blocks
+int comparePointers(Loc loc, TOK op, Type *type, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2);
+
+// Return eptr op e2, where eptr is a pointer, e2 is an integer,
+// and op is TOKadd or TOKmin
+UnionExp pointerArithmetic(Loc loc, TOK op, Type *type,
+    Expression *eptr, Expression *e2);
+
+// True if conversion from type 'from' to 'to' involves a reinterpret_cast
+// floating point -> integer or integer -> floating point
+bool isFloatIntPaint(Type *to, Type *from);
+
+// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
+Expression *paintFloatInt(Expression *fromVal, Type *to);
+
+/// Return true if t is an AA
+bool isAssocArray(Type *t);
+
+/// Given a template AA type, extract the corresponding built-in AA type
+TypeAArray *toBuiltinAAType(Type *t);
+
+/*  Given an AA literal 'ae', and a key 'e2':
+ *  Return ae[e2] if present, or NULL if not found.
+ *  Return TOKcantexp on error.
+ */
+Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2);
+
+/// True if type is TypeInfo_Class
+bool isTypeInfo_Class(Type *type);
+
+
+/***********************************************
+      COW const-folding operations
+***********************************************/
+
+/// Return true if non-pointer expression e can be compared
+/// with >,is, ==, etc, using ctfeCmp, ctfeEquals, ctfeIdentity
+bool isCtfeComparable(Expression *e);
+
+/// Evaluate ==, !=.  Resolves slices before comparing. Returns 0 or 1
+int ctfeEqual(Loc loc, TOK op, Expression *e1, Expression *e2);
+
+/// Evaluate is, !is.  Resolves slices before comparing. Returns 0 or 1
+int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2);
+
+/// Returns rawCmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int specificCmp(TOK op, int rawCmp);
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2);
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2);
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int realCmp(TOK op, real_t r1, real_t r2);
+
+/// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
+int ctfeCmp(Loc loc, TOK op, Expression *e1, Expression *e2);
+
+/// Returns e1 ~ e2. Resolves slices before concatenation.
+UnionExp ctfeCat(Type *type, Expression *e1, Expression *e2);
+
+/// Same as for constfold.Index, except that it only works for static arrays,
+/// dynamic arrays, and strings.
+Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx);
+
+/// Cast 'e' of type 'type' to type 'to'.
+Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e);
+
+
+#endif /* DMD_CTFE_H */
diff --git a/gcc/d/dfrontend/ctfeexpr.c b/gcc/d/dfrontend/ctfeexpr.c
new file mode 100644
index 00000000000..e18812afa21
--- /dev/null
+++ b/gcc/d/dfrontend/ctfeexpr.c
@@ -0,0 +1,2112 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/ctfeexpr.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>                     // mem{cpy|set}()
+#include <new>
+
+#include "rmem.h"
+
+#include "expression.h"
+#include "declaration.h"
+#include "aggregate.h"
+// for AssocArray
+#include "id.h"
+#include "utf.h"
+#include "template.h"
+#include "ctfe.h"
+#include "target.h"
+
+int RealEquals(real_t x1, real_t x2);
+
+/************** ClassReferenceExp ********************************************/
+
+ClassReferenceExp::ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type)
+    : Expression(loc, TOKclassreference, sizeof(ClassReferenceExp))
+{
+    assert(lit && lit->sd && lit->sd->isClassDeclaration());
+    this->value = lit;
+    this->type = type;
+}
+
+ClassDeclaration *ClassReferenceExp::originalClass()
+{
+    return value->sd->isClassDeclaration();
+}
+
+// Return index of the field, or -1 if not found
+int ClassReferenceExp::getFieldIndex(Type *fieldtype, unsigned fieldoffset)
+{
+    ClassDeclaration *cd = originalClass();
+    unsigned fieldsSoFar = 0;
+    for (size_t j = 0; j < value->elements->dim; j++)
+    {
+        while (j - fieldsSoFar >= cd->fields.dim)
+        {
+            fieldsSoFar += cd->fields.dim;
+            cd = cd->baseClass;
+        }
+        VarDeclaration *v2 = cd->fields[j - fieldsSoFar];
+        if (fieldoffset == v2->offset &&
+            fieldtype->size() == v2->type->size())
+        {
+            return (int)(value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar));
+        }
+    }
+    return -1;
+}
+
+// Return index of the field, or -1 if not found
+// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
+int ClassReferenceExp::findFieldIndexByName(VarDeclaration *v)
+{
+    ClassDeclaration *cd = originalClass();
+    size_t fieldsSoFar = 0;
+    for (size_t j = 0; j < value->elements->dim; j++)
+    {
+        while (j - fieldsSoFar >= cd->fields.dim)
+        {
+            fieldsSoFar += cd->fields.dim;
+            cd = cd->baseClass;
+        }
+        VarDeclaration *v2 = cd->fields[j - fieldsSoFar];
+        if (v == v2)
+        {
+            return (int)(value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar));
+        }
+    }
+    return -1;
+}
+
+/************** VoidInitExp ********************************************/
+
+VoidInitExp::VoidInitExp(VarDeclaration *var, Type *type)
+    : Expression(var->loc, TOKvoid, sizeof(VoidInitExp))
+{
+    this->var = var;
+    this->type = var->type;
+}
+
+const char *VoidInitExp::toChars()
+{
+    return (char *)"void";
+}
+
+// Return index of the field, or -1 if not found
+// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
+int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v)
+{
+    for (size_t i = 0; i < sd->fields.dim; ++i)
+    {
+        if (sd->fields[i] == v)
+            return (int)i;
+    }
+    return -1;
+}
+
+/************** ThrownExceptionExp ********************************************/
+
+ThrownExceptionExp::ThrownExceptionExp(Loc loc, ClassReferenceExp *victim) : Expression(loc, TOKthrownexception, sizeof(ThrownExceptionExp))
+{
+    this->thrown = victim;
+    this->type = victim->type;
+}
+
+const char *ThrownExceptionExp::toChars()
+{
+    return (char *)"CTFE ThrownException";
+}
+
+// Generate an error message when this exception is not caught
+void ThrownExceptionExp::generateUncaughtError()
+{
+    Expression *e = resolveSlice((*thrown->value->elements)[0]);
+    StringExp *se = e->toStringExp();
+    thrown->error("uncaught CTFE exception %s(%s)", thrown->type->toChars(), se ? se->toChars() : e->toChars());
+
+    /* Also give the line where the throw statement was. We won't have it
+     * in the case where the ThrowStatement is generated internally
+     * (eg, in ScopeStatement)
+     */
+    if (loc.filename && !loc.equals(thrown->loc))
+        errorSupplemental(loc, "thrown from here");
+}
+
+// True if 'e' is CTFEExp::cantexp, or an exception
+bool exceptionOrCantInterpret(Expression *e)
+{
+    return e && (e->op == TOKcantexp || e->op == TOKthrownexception);
+}
+
+/********************** CTFEExp ******************************************/
+
+CTFEExp *CTFEExp::cantexp;
+CTFEExp *CTFEExp::voidexp;
+CTFEExp *CTFEExp::breakexp;
+CTFEExp *CTFEExp::continueexp;
+CTFEExp *CTFEExp::gotoexp;
+
+CTFEExp::CTFEExp(TOK tok)
+    : Expression(Loc(), tok, sizeof(CTFEExp))
+{
+    type = Type::tvoid;
+}
+
+const char *CTFEExp::toChars()
+{
+    switch (op)
+    {
+        case TOKcantexp:    return (char *)"<cant>";
+        case TOKvoidexp:    return (char *)"<void>";
+        case TOKbreak:      return (char *)"<break>";
+        case TOKcontinue:   return (char *)"<continue>";
+        case TOKgoto:       return (char *)"<goto>";
+        default:            assert(0);  return NULL;
+    }
+}
+
+Expression *UnionExp::copy()
+{
+    Expression *e = exp();
+    //if (e->size > sizeof(u)) printf("%s\n", Token::toChars(e->op));
+    assert(e->size <= sizeof(u));
+    if (e->op == TOKcantexp)    return CTFEExp::cantexp;
+    if (e->op == TOKvoidexp)    return CTFEExp::voidexp;
+    if (e->op == TOKbreak)      return CTFEExp::breakexp;
+    if (e->op == TOKcontinue)   return CTFEExp::continueexp;
+    if (e->op == TOKgoto)       return CTFEExp::gotoexp;
+    return e->copy();
+}
+
+/************** Aggregate literals (AA/string/array/struct) ******************/
+
+// Given expr, which evaluates to an array/AA/string literal,
+// return true if it needs to be copied
+bool needToCopyLiteral(Expression *expr)
+{
+    for (;;)
+    {
+        switch (expr->op)
+        {
+            case TOKarrayliteral:
+                return ((ArrayLiteralExp *)expr)->ownedByCtfe == OWNEDcode;
+            case TOKassocarrayliteral:
+                return ((AssocArrayLiteralExp *)expr)->ownedByCtfe == OWNEDcode;
+            case TOKstructliteral:
+                return ((StructLiteralExp *)expr)->ownedByCtfe == OWNEDcode;
+            case TOKstring:
+            case TOKthis:
+            case TOKvar:
+                return false;
+            case TOKassign:
+                return false;
+            case TOKindex:
+            case TOKdotvar:
+            case TOKslice:
+            case TOKcast:
+                expr = ((UnaExp *)expr)->e1;
+                continue;
+            case TOKcat:
+                return needToCopyLiteral(((BinExp *)expr)->e1) ||
+                    needToCopyLiteral(((BinExp *)expr)->e2);
+            case TOKcatass:
+                expr = ((BinExp *)expr)->e2;
+                continue;
+            default:
+                return false;
+        }
+    }
+}
+
+Expressions *copyLiteralArray(Expressions *oldelems, Expression *basis = NULL)
+{
+    if (!oldelems)
+        return oldelems;
+    CtfeStatus::numArrayAllocs++;
+    Expressions *newelems = new Expressions();
+    newelems->setDim(oldelems->dim);
+    for (size_t i = 0; i < oldelems->dim; i++)
+    {
+        Expression *el = (*oldelems)[i];
+        if (!el)
+            el = basis;
+        (*newelems)[i] = copyLiteral(el).copy();
+    }
+    return newelems;
+}
+
+// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
+// This value will be used for in-place modification.
+UnionExp copyLiteral(Expression *e)
+{
+    UnionExp ue;
+    if (e->op == TOKstring) // syntaxCopy doesn't make a copy for StringExp!
+    {
+        StringExp *se = (StringExp *)e;
+        utf8_t *s = (utf8_t *)mem.xcalloc(se->len + 1, se->sz);
+        memcpy(s, se->string, se->len * se->sz);
+        new(&ue) StringExp(se->loc, s, se->len);
+        StringExp *se2 = (StringExp *)ue.exp();
+        se2->committed = se->committed;
+        se2->postfix = se->postfix;
+        se2->type = se->type;
+        se2->sz = se->sz;
+        se2->ownedByCtfe = OWNEDctfe;
+        return ue;
+    }
+    if (e->op == TOKarrayliteral)
+    {
+        ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
+        Expression *basis = ale->basis ? copyLiteral(ale->basis).copy() : NULL;
+        Expressions *elements = copyLiteralArray(ale->elements, ale->basis);
+
+        new(&ue) ArrayLiteralExp(e->loc, elements);
+
+        ArrayLiteralExp *r = (ArrayLiteralExp *)ue.exp();
+        r->type = e->type;
+        r->ownedByCtfe = OWNEDctfe;
+        return ue;
+    }
+    if (e->op == TOKassocarrayliteral)
+    {
+        AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
+        new(&ue) AssocArrayLiteralExp(e->loc, copyLiteralArray(aae->keys), copyLiteralArray(aae->values));
+        AssocArrayLiteralExp *r = (AssocArrayLiteralExp *)ue.exp();
+        r->type = e->type;
+        r->ownedByCtfe = OWNEDctfe;
+        return ue;
+    }
+    if (e->op == TOKstructliteral)
+    {
+        /* syntaxCopy doesn't work for struct literals, because of a nasty special
+         * case: block assignment is permitted inside struct literals, eg,
+         * an int[4] array can be initialized with a single int.
+         */
+        StructLiteralExp *sle = (StructLiteralExp *)e;
+        Expressions *oldelems = sle->elements;
+        Expressions * newelems = new Expressions();
+        newelems->setDim(oldelems->dim);
+        for (size_t i = 0; i < newelems->dim; i++)
+        {
+            // We need the struct definition to detect block assignment
+            VarDeclaration *v = sle->sd->fields[i];
+            Expression *m = (*oldelems)[i];
+
+            // If it is a void assignment, use the default initializer
+            if (!m)
+                m = voidInitLiteral(v->type, v).copy();
+
+            if (v->type->ty == Tarray || v->type->ty == Taarray)
+            {
+                // Don't have to copy array references
+            }
+            else
+            {
+                // Buzilla 15681: Copy the source element always.
+                m = copyLiteral(m).copy();
+
+                // Block assignment from inside struct literals
+                if (v->type->ty != m->type->ty && v->type->ty == Tsarray)
+                {
+                    TypeSArray *tsa = (TypeSArray *)v->type;
+                    size_t len = (size_t)tsa->dim->toInteger();
+                    m = createBlockDuplicatedArrayLiteral(e->loc, v->type, m, len);
+                }
+            }
+            (*newelems)[i] = m;
+        }
+        new(&ue) StructLiteralExp(e->loc, sle->sd, newelems, sle->stype);
+        StructLiteralExp *r = (StructLiteralExp *)ue.exp();
+        r->type = e->type;
+        r->ownedByCtfe = OWNEDctfe;
+        r->origin = ((StructLiteralExp *)e)->origin;
+        return ue;
+    }
+    if (e->op == TOKfunction || e->op == TOKdelegate ||
+        e->op == TOKsymoff || e->op == TOKnull ||
+        e->op == TOKvar || e->op == TOKdotvar ||
+        e->op == TOKint64 || e->op == TOKfloat64 ||
+        e->op == TOKchar || e->op == TOKcomplex80 ||
+        e->op == TOKvoid || e->op == TOKvector ||
+        e->op == TOKtypeid)
+    {
+        // Simple value types
+        // Keep e1 for DelegateExp and DotVarExp
+        new(&ue) UnionExp(e);
+        Expression *r = ue.exp();
+        r->type = e->type;
+        return ue;
+    }
+    if (isPointer(e->type))
+    {
+        // For pointers, we only do a shallow copy.
+        if (e->op == TOKaddress)
+            new(&ue) AddrExp(e->loc, ((AddrExp *)e)->e1);
+        else if (e->op == TOKindex)
+            new(&ue) IndexExp(e->loc, ((IndexExp *)e)->e1, ((IndexExp *)e)->e2);
+        else if (e->op == TOKdotvar)
+        {
+            new(&ue) DotVarExp(e->loc, ((DotVarExp *)e)->e1,
+                ((DotVarExp *)e)->var, ((DotVarExp *)e)->hasOverloads);
+        }
+        else
+            assert(0);
+        Expression *r = ue.exp();
+        r->type = e->type;
+        return ue;
+    }
+    if (e->op == TOKslice)
+    {
+        SliceExp *se = (SliceExp *)e;
+        if (se->type->toBasetype()->ty == Tsarray)
+        {
+            // same with resolveSlice()
+            if (se->e1->op == TOKnull)
+            {
+                new(&ue) NullExp(se->loc, se->type);
+                return ue;
+            }
+            ue = Slice(se->type, se->e1, se->lwr, se->upr);
+            assert(ue.exp()->op == TOKarrayliteral);
+            ArrayLiteralExp *r = (ArrayLiteralExp *)ue.exp();
+            r->elements = copyLiteralArray(r->elements);
+            r->ownedByCtfe = OWNEDctfe;
+            return ue;
+        }
+        else
+        {
+            // Array slices only do a shallow copy
+            new(&ue) SliceExp(e->loc, se->e1, se->lwr, se->upr);
+            Expression *r = ue.exp();
+            r->type = e->type;
+            return ue;
+        }
+    }
+    if (e->op == TOKclassreference)
+    {
+        new(&ue) ClassReferenceExp(e->loc, ((ClassReferenceExp *)e)->value, e->type);
+        return ue;
+    }
+    if (e->op == TOKerror)
+    {
+        new(&ue) UnionExp(e);
+        return ue;
+    }
+    e->error("CTFE internal error: literal %s", e->toChars());
+    assert(0);
+    return ue;
+}
+
+/* Deal with type painting.
+ * Type painting is a major nuisance: we can't just set
+ * e->type = type, because that would change the original literal.
+ * But, we can't simply copy the literal either, because that would change
+ * the values of any pointers.
+ */
+Expression *paintTypeOntoLiteral(Type *type, Expression *lit)
+{
+    if (lit->type->equals(type))
+        return lit;
+    return paintTypeOntoLiteralCopy(type, lit).copy();
+}
+
+UnionExp paintTypeOntoLiteralCopy(Type *type, Expression *lit)
+{
+    UnionExp ue;
+
+    if (lit->type->equals(type))
+    {
+        new(&ue) UnionExp(lit);
+        return ue;
+    }
+
+    // If it is a cast to inout, retain the original type of the referenced part.
+    if (type->hasWild() && type->hasPointers())
+    {
+        new(&ue) UnionExp(lit);
+        ue.exp()->type = type;
+        return ue;
+    }
+
+    if (lit->op == TOKslice)
+    {
+        SliceExp *se = (SliceExp *)lit;
+        new(&ue) SliceExp(lit->loc, se->e1, se->lwr, se->upr);
+    }
+    else if (lit->op == TOKindex)
+    {
+        IndexExp *ie = (IndexExp *)lit;
+        new(&ue) IndexExp(lit->loc, ie->e1, ie->e2);
+    }
+    else if (lit->op == TOKarrayliteral)
+    {
+        new(&ue) SliceExp(lit->loc, lit,
+            new IntegerExp(Loc(), 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit).copy());
+    }
+    else if (lit->op == TOKstring)
+    {
+        // For strings, we need to introduce another level of indirection
+        new(&ue) SliceExp(lit->loc, lit,
+            new IntegerExp(Loc(), 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit).copy());
+    }
+    else if (lit->op == TOKassocarrayliteral)
+    {
+        AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)lit;
+        // TODO: we should be creating a reference to this AAExp, not
+        // just a ref to the keys and values.
+        OwnedBy wasOwned = aae->ownedByCtfe;
+        new(&ue) AssocArrayLiteralExp(lit->loc, aae->keys, aae->values);
+        aae = (AssocArrayLiteralExp *)ue.exp();
+        aae->ownedByCtfe = wasOwned;
+    }
+    else
+    {
+        // Can't type paint from struct to struct*; this needs another
+        // level of indirection
+        if (lit->op == TOKstructliteral && isPointer(type))
+            lit->error("CTFE internal error: painting %s", type->toChars());
+        ue = copyLiteral(lit);
+    }
+    ue.exp()->type = type;
+    return ue;
+}
+
+Expression *resolveSlice(Expression *e)
+{
+    if (e->op != TOKslice)
+        return e;
+    SliceExp *se = (SliceExp *)e;
+    if (se->e1->op == TOKnull)
+        return se->e1;
+    return Slice(e->type, se->e1, se->lwr, se->upr).copy();
+}
+
+/* Determine the array length, without interpreting it.
+ * e must be an array literal, or a slice
+ * It's very wasteful to resolve the slice when we only
+ * need the length.
+ */
+uinteger_t resolveArrayLength(Expression *e)
+{
+    if (e->op == TOKvector)
+        e = ((VectorExp *)e)->e1;
+
+    if (e->op == TOKnull)
+        return 0;
+    if (e->op == TOKslice)
+    {
+        uinteger_t ilo = ((SliceExp *)e)->lwr->toInteger();
+        uinteger_t iup = ((SliceExp *)e)->upr->toInteger();
+        return iup - ilo;
+    }
+    if (e->op == TOKstring)
+    {
+        return ((StringExp *)e)->len;
+    }
+    if (e->op == TOKarrayliteral)
+    {
+        ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
+        return ale->elements ? ale->elements->dim : 0;
+    }
+    if (e->op == TOKassocarrayliteral)
+    {
+        AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e;
+        return ale->keys->dim;
+    }
+    assert(0);
+    return 0;
+}
+
+/******************************
+ * Helper for NewExp
+ * Create an array literal consisting of 'elem' duplicated 'dim' times.
+ * Params:
+ *      loc = source location where the interpretation occurs
+ *      type = target type of the result
+ *      elem = the source of array element, it will be owned by the result
+ *      dim = element number of the result
+ * Returns:
+ *      Constructed ArrayLiteralExp
+ */
+ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type,
+        Expression *elem, size_t dim)
+{
+    if (type->ty == Tsarray && type->nextOf()->ty == Tsarray && elem->type->ty != Tsarray)
+    {
+        // If it is a multidimensional array literal, do it recursively
+        TypeSArray *tsa = (TypeSArray *)type->nextOf();
+        size_t len = (size_t)tsa->dim->toInteger();
+        elem = createBlockDuplicatedArrayLiteral(loc, type->nextOf(), elem, len);
+    }
+
+    // Buzilla 15681
+    Type *tb = elem->type->toBasetype();
+    const bool mustCopy = tb->ty == Tstruct || tb->ty == Tsarray;
+
+    Expressions *elements = new Expressions();
+    elements->setDim(dim);
+    for (size_t i = 0; i < dim; i++)
+    {
+        (*elements)[i] = mustCopy ? copyLiteral(elem).copy() : elem;
+    }
+    ArrayLiteralExp *ale = new ArrayLiteralExp(loc, elements);
+    ale->type = type;
+    ale->ownedByCtfe = OWNEDctfe;
+    return ale;
+}
+
+/******************************
+ * Helper for NewExp
+ * Create a string literal consisting of 'value' duplicated 'dim' times.
+ */
+StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type,
+        unsigned value, size_t dim, unsigned char sz)
+{
+    utf8_t *s = (utf8_t *)mem.xcalloc(dim + 1, sz);
+    for (size_t elemi = 0; elemi < dim; ++elemi)
+    {
+        switch (sz)
+        {
+            case 1:     s[elemi] = (utf8_t)value; break;
+            case 2:     ((unsigned short *)s)[elemi] = (unsigned short)value; break;
+            case 4:     ((unsigned *)s)[elemi] = value; break;
+            default:    assert(0);
+        }
+    }
+    StringExp *se = new StringExp(loc, s, dim);
+    se->type = type;
+    se->sz = sz;
+    se->committed = true;
+    se->ownedByCtfe = OWNEDctfe;
+    return se;
+}
+
+// Return true if t is an AA
+bool isAssocArray(Type *t)
+{
+    t = t->toBasetype();
+    if (t->ty == Taarray)
+        return true;
+    return false;
+}
+
+// Given a template AA type, extract the corresponding built-in AA type
+TypeAArray *toBuiltinAAType(Type *t)
+{
+    t = t->toBasetype();
+    if (t->ty == Taarray)
+        return (TypeAArray *)t;
+    assert(0);
+    return NULL;
+}
+
+/************** TypeInfo operations ************************************/
+
+// Return true if type is TypeInfo_Class
+bool isTypeInfo_Class(Type *type)
+{
+    return type->ty == Tclass &&
+        (Type::dtypeinfo == ((TypeClass *)type)->sym ||
+         Type::dtypeinfo->isBaseOf(((TypeClass *)type)->sym, NULL));
+}
+
+/************** Pointer operations ************************************/
+
+// Return true if t is a pointer (not a function pointer)
+bool isPointer(Type *t)
+{
+    Type * tb = t->toBasetype();
+    return tb->ty == Tpointer && tb->nextOf()->ty != Tfunction;
+}
+
+// For CTFE only. Returns true if 'e' is true or a non-null pointer.
+bool isTrueBool(Expression *e)
+{
+    return e->isBool(true) ||
+           ((e->type->ty == Tpointer || e->type->ty == Tclass) && e->op != TOKnull);
+}
+
+/* Is it safe to convert from srcPointee* to destPointee* ?
+ * srcPointee is the genuine type (never void).
+ * destPointee may be void.
+ */
+bool isSafePointerCast(Type *srcPointee, Type *destPointee)
+{
+    // It's safe to cast S** to D** if it's OK to cast S* to D*
+    while (srcPointee->ty == Tpointer && destPointee->ty == Tpointer)
+    {
+        srcPointee = srcPointee->nextOf();
+        destPointee = destPointee->nextOf();
+    }
+
+    // It's OK if both are the same (modulo const)
+    if (srcPointee->constConv(destPointee))
+        return true;
+
+    // It's OK if function pointers differ only in safe/pure/nothrow
+    if (srcPointee->ty == Tfunction && destPointee->ty == Tfunction)
+        return srcPointee->covariant(destPointee) == 1;
+
+    // it's OK to cast to void*
+    if (destPointee->ty == Tvoid)
+        return true;
+
+    // It's OK to cast from V[K] to void*
+    if (srcPointee->ty == Taarray && destPointee == Type::tvoidptr)
+        return true;
+
+    // It's OK if they are the same size (static array of) integers, eg:
+    //     int*     --> uint*
+    //     int[5][] --> uint[5][]
+    if (srcPointee->ty == Tsarray && destPointee->ty == Tsarray)
+    {
+        if (srcPointee->size() != destPointee->size())
+            return false;
+        srcPointee = srcPointee->baseElemOf();
+        destPointee = destPointee->baseElemOf();
+    }
+    return srcPointee->isintegral() &&
+           destPointee->isintegral() &&
+           srcPointee->size() == destPointee->size();
+}
+
+Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs)
+{
+    *ofs = 0;
+    if (e->op == TOKaddress)
+        e = ((AddrExp *)e)->e1;
+    if (e->op == TOKsymoff)
+        *ofs = ((SymOffExp *)e)->offset;
+    if (e->op == TOKdotvar)
+    {
+        Expression *ex = ((DotVarExp *)e)->e1;
+        VarDeclaration *v = ((DotVarExp *)e)->var->isVarDeclaration();
+        assert(v);
+        StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex;
+        // We can't use getField, because it makes a copy
+        unsigned i;
+        if (ex->op == TOKclassreference)
+            i = ((ClassReferenceExp *)ex)->getFieldIndex(e->type, v->offset);
+        else
+            i = se->getFieldIndex(e->type, v->offset);
+        e = (*se->elements)[i];
+    }
+    if (e->op == TOKindex)
+    {
+        IndexExp *ie = (IndexExp *)e;
+        // Note that each AA element is part of its own memory block
+        if ((ie->e1->type->ty == Tarray ||
+             ie->e1->type->ty == Tsarray ||
+             ie->e1->op == TOKstring ||
+             ie->e1->op == TOKarrayliteral) &&
+            ie->e2->op == TOKint64)
+        {
+            *ofs = ie->e2->toInteger();
+            return ie->e1;
+        }
+    }
+    if (e->op == TOKslice && e->type->toBasetype()->ty == Tsarray)
+    {
+        SliceExp *se = (SliceExp *)e;
+        if ((se->e1->type->ty == Tarray ||
+             se->e1->type->ty == Tsarray ||
+             se->e1->op == TOKstring ||
+             se->e1->op == TOKarrayliteral) &&
+            se->lwr->op == TOKint64)
+        {
+            *ofs = se->lwr->toInteger();
+            return se->e1;
+        }
+    }
+    return e;
+}
+
+/** Return true if agg1 and agg2 are pointers to the same memory block
+*/
+bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2)
+{
+    if (agg1 == agg2)
+        return true;
+
+    // For integers cast to pointers, we regard them as non-comparable
+    // unless they are identical. (This may be overly strict).
+    if (agg1->op == TOKint64 && agg2->op == TOKint64 &&
+        agg1->toInteger() == agg2->toInteger())
+    {
+        return true;
+    }
+
+    // Note that type painting can occur with VarExp, so we
+    // must compare the variables being pointed to.
+    if (agg1->op == TOKvar && agg2->op == TOKvar &&
+        ((VarExp *)agg1)->var == ((VarExp *)agg2)->var)
+    {
+        return true;
+    }
+    if (agg1->op == TOKsymoff && agg2->op == TOKsymoff &&
+        ((SymOffExp *)agg1)->var == ((SymOffExp *)agg2)->var)
+    {
+        return true;
+    }
+
+    return false;
+}
+
+// return e1 - e2 as an integer, or error if not possible
+UnionExp pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+    UnionExp ue;
+    dinteger_t ofs1, ofs2;
+    Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
+    Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
+    if (agg1 == agg2)
+    {
+        Type *pointee = ((TypePointer *)agg1->type)->next;
+        dinteger_t sz = pointee->size();
+        new(&ue) IntegerExp(loc, (ofs1 - ofs2) * sz, type);
+    }
+    else if (agg1->op == TOKstring && agg2->op == TOKstring)
+    {
+        if (((StringExp *)agg1)->string == ((StringExp *)agg2)->string)
+        {
+            Type *pointee = ((TypePointer *)agg1->type)->next;
+            dinteger_t sz = pointee->size();
+            new(&ue) IntegerExp(loc, (ofs1 - ofs2) * sz, type);
+        }
+    }
+    else if (agg1->op == TOKsymoff && agg2->op == TOKsymoff &&
+             ((SymOffExp *)agg1)->var == ((SymOffExp *)agg2)->var)
+    {
+        new(&ue) IntegerExp(loc, ofs1 - ofs2, type);
+    }
+    else
+    {
+        error(loc, "%s - %s cannot be interpreted at compile time: cannot subtract "
+            "pointers to two different memory blocks",
+            e1->toChars(), e2->toChars());
+        new(&ue) CTFEExp(TOKcantexp);
+    }
+    return ue;
+}
+
+// Return eptr op e2, where eptr is a pointer, e2 is an integer,
+// and op is TOKadd or TOKmin
+UnionExp pointerArithmetic(Loc loc, TOK op, Type *type,
+    Expression *eptr, Expression *e2)
+{
+    UnionExp ue;
+
+    if (eptr->type->nextOf()->ty == Tvoid)
+    {
+        error(loc, "cannot perform arithmetic on void* pointers at compile time");
+      Lcant:
+        new(&ue) CTFEExp(TOKcantexp);
+        return ue;
+    }
+
+    dinteger_t ofs1;
+    if (eptr->op == TOKaddress)
+        eptr = ((AddrExp *)eptr)->e1;
+    Expression *agg1 = getAggregateFromPointer(eptr, &ofs1);
+    if (agg1->op == TOKsymoff)
+    {
+        if (((SymOffExp *)agg1)->var->type->ty != Tsarray)
+        {
+            error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time");
+            goto Lcant;
+        }
+    }
+    else if (agg1->op != TOKstring && agg1->op != TOKarrayliteral)
+    {
+        error(loc, "cannot perform pointer arithmetic on non-arrays at compile time");
+        goto Lcant;
+    }
+    dinteger_t ofs2 = e2->toInteger();
+
+    Type *pointee = ((TypeNext *)agg1->type->toBasetype())->next;
+    dinteger_t sz = pointee->size();
+
+    sinteger_t indx;
+    dinteger_t len;
+    if (agg1->op == TOKsymoff)
+    {
+        indx = ofs1 / sz;
+        len = ((TypeSArray *)((SymOffExp *)agg1)->var->type)->dim->toInteger();
+    }
+    else
+    {
+        Expression *dollar = ArrayLength(Type::tsize_t, agg1).copy();
+        assert(!CTFEExp::isCantExp(dollar));
+        indx = ofs1;
+        len = dollar->toInteger();
+    }
+    if (op == TOKadd || op == TOKaddass || op == TOKplusplus)
+        indx += ofs2 / sz;
+    else if (op == TOKmin || op == TOKminass || op == TOKminusminus)
+        indx -= ofs2 / sz;
+    else
+    {
+        error(loc, "CTFE internal error: bad pointer operation");
+        goto Lcant;
+    }
+
+    if (indx < 0 || len < indx)
+    {
+        error(loc, "cannot assign pointer to index %lld inside memory block [0..%lld]", indx, len);
+        goto Lcant;
+    }
+
+    if (agg1->op == TOKsymoff)
+    {
+        new(&ue) SymOffExp(loc, ((SymOffExp *)agg1)->var, indx * sz);
+        SymOffExp *se = (SymOffExp *)ue.exp();
+        se->type = type;
+        return ue;
+    }
+
+    if (agg1->op != TOKarrayliteral && agg1->op != TOKstring)
+    {
+        error(loc, "CTFE internal error: pointer arithmetic %s", agg1->toChars());
+        goto Lcant;
+    }
+
+    if (eptr->type->toBasetype()->ty == Tsarray)
+    {
+        dinteger_t dim = ((TypeSArray *)eptr->type->toBasetype())->dim->toInteger();
+
+        // Create a CTFE pointer &agg1[indx .. indx+dim]
+        SliceExp *se = new SliceExp(loc, agg1,
+            new IntegerExp(loc, indx,       Type::tsize_t),
+            new IntegerExp(loc, indx + dim, Type::tsize_t));
+        se->type = type->toBasetype()->nextOf();
+        new(&ue) AddrExp(loc, se);
+        ue.exp()->type = type;
+        return ue;
+    }
+
+    // Create a CTFE pointer &agg1[indx]
+    IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t);
+    Expression *ie = new IndexExp(loc, agg1, ofs);
+    ie->type = type->toBasetype()->nextOf();    // Bugzilla 13992
+    new(&ue) AddrExp(loc, ie);
+    ue.exp()->type = type;
+    return ue;
+}
+
+// Return 1 if true, 0 if false
+// -1 if comparison is illegal because they point to non-comparable memory blocks
+int comparePointers(Loc loc, TOK op, Type *type, Expression *agg1, dinteger_t ofs1,
+        Expression *agg2, dinteger_t ofs2)
+{
+    if (pointToSameMemoryBlock(agg1, agg2))
+    {
+        int n;
+        switch (op)
+        {
+        case TOKlt:          n = (ofs1 <  ofs2); break;
+        case TOKle:          n = (ofs1 <= ofs2); break;
+        case TOKgt:          n = (ofs1 >  ofs2); break;
+        case TOKge:          n = (ofs1 >= ofs2); break;
+        case TOKidentity:
+        case TOKequal:       n = (ofs1 == ofs2); break;
+        case TOKnotidentity:
+        case TOKnotequal:    n = (ofs1 != ofs2); break;
+        default:
+            assert(0);
+        }
+        return n;
+    }
+    bool null1 = (agg1->op == TOKnull);
+    bool null2 = (agg2->op == TOKnull);
+
+    int cmp;
+    if (null1 || null2)
+    {
+        switch (op)
+        {
+        case TOKlt:   cmp =  null1 && !null2;   break;
+        case TOKgt:   cmp = !null1 &&  null2;   break;
+        case TOKle:   cmp = null1;              break;
+        case TOKge:   cmp = null2;              break;
+        case TOKidentity:
+        case TOKequal:
+        case TOKnotidentity: // 'cmp' gets inverted below
+        case TOKnotequal:
+            cmp = (null1 == null2);
+            break;
+        default:
+            assert(0);
+        }
+    }
+    else
+    {
+        switch (op)
+        {
+        case TOKidentity:
+        case TOKequal:
+        case TOKnotidentity: // 'cmp' gets inverted below
+        case TOKnotequal:
+            cmp = 0;
+            break;
+        default:
+            return -1; // memory blocks are different
+        }
+    }
+    if (op == TOKnotidentity || op == TOKnotequal)
+        cmp ^= 1;
+    return cmp;
+}
+
+// True if conversion from type 'from' to 'to' involves a reinterpret_cast
+// floating point -> integer or integer -> floating point
+bool isFloatIntPaint(Type *to, Type *from)
+{
+    return from->size() == to->size() &&
+           (from->isintegral() && to->isfloating() ||
+            from->isfloating() && to->isintegral());
+}
+
+// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
+Expression *paintFloatInt(Expression *fromVal, Type *to)
+{
+    if (exceptionOrCantInterpret(fromVal))
+        return fromVal;
+
+    assert(to->size() == 4 || to->size() == 8);
+    return Target::paintAsType(fromVal, to);
+}
+
+/******** Constant folding, with support for CTFE ***************************/
+
+/// Return true if non-pointer expression e can be compared
+/// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity
+bool isCtfeComparable(Expression *e)
+{
+    if (e->op == TOKslice)
+        e = ((SliceExp *)e)->e1;
+
+    if (e->isConst() != 1)
+    {
+        if (e->op == TOKnull ||
+            e->op == TOKstring ||
+            e->op == TOKfunction ||
+            e->op == TOKdelegate ||
+            e->op == TOKarrayliteral ||
+            e->op == TOKstructliteral ||
+            e->op == TOKassocarrayliteral ||
+            e->op == TOKclassreference)
+        {
+            return true;
+        }
+        // Bugzilla 14123: TypeInfo object is comparable in CTFE
+        if (e->op == TOKtypeid)
+            return true;
+
+        return false;
+    }
+    return true;
+}
+
+/// Map TOK comparison ops
+template <typename N>
+static bool numCmp(TOK op, N n1, N n2)
+{
+    switch (op)
+    {
+        case TOKlt:
+            return n1 <  n2;
+        case TOKle:
+            return n1 <= n2;
+        case TOKgt:
+            return n1 >  n2;
+        case TOKge:
+            return n1 >= n2;
+
+        default:
+            assert(0);
+    }
+}
+
+/// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int specificCmp(TOK op, int rawCmp)
+{
+    return numCmp<int>(op, rawCmp, 0);
+}
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2)
+{
+    return numCmp<dinteger_t>(op, n1, n2);
+}
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2)
+{
+    return numCmp<sinteger_t>(op, n1, n2);
+}
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int realCmp(TOK op, real_t r1, real_t r2)
+{
+    // Don't rely on compiler, handle NAN arguments separately
+    if (CTFloat::isNaN(r1) || CTFloat::isNaN(r2)) // if unordered
+    {
+        switch (op)
+        {
+            case TOKlt:
+            case TOKle:
+            case TOKgt:
+            case TOKge:
+                return 0;
+
+            default:
+                assert(0);
+        }
+    }
+    else
+    {
+        return numCmp<real_t>(op, r1, r2);
+    }
+}
+
+int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2);
+
+/* Conceptually the same as memcmp(e1, e2).
+ * e1 and e2 may be strings, arrayliterals, or slices.
+ * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
+ * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
+ */
+int ctfeCmpArrays(Loc loc, Expression *e1, Expression *e2, uinteger_t len)
+{
+    // Resolve slices, if necessary
+    uinteger_t lo1 = 0;
+    uinteger_t lo2 = 0;
+
+    Expression *x = e1;
+    if (x->op == TOKslice)
+    {
+        lo1 = ((SliceExp *)x)->lwr->toInteger();
+        x = ((SliceExp *)x)->e1;
+    }
+    StringExp *se1 = (x->op == TOKstring) ? (StringExp *)x : NULL;
+    ArrayLiteralExp *ae1 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : NULL;
+
+    x = e2;
+    if (x->op == TOKslice)
+    {
+        lo2 = ((SliceExp *)x)->lwr->toInteger();
+        x = ((SliceExp *)x)->e1;
+    }
+    StringExp *se2 = (x->op == TOKstring) ? (StringExp *)x : NULL;
+    ArrayLiteralExp *ae2 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : NULL;
+
+    // Now both must be either TOKarrayliteral or TOKstring
+    if (se1 && se2)
+        return sliceCmpStringWithString(se1, se2, (size_t)lo1, (size_t)lo2, (size_t)len);
+    if (se1 && ae2)
+        return sliceCmpStringWithArray(se1, ae2, (size_t)lo1, (size_t)lo2, (size_t)len);
+    if (se2 && ae1)
+        return -sliceCmpStringWithArray(se2, ae1, (size_t)lo2, (size_t)lo1, (size_t)len);
+
+    assert (ae1 && ae2);
+    // Comparing two array literals. This case is potentially recursive.
+    // If they aren't strings, we just need an equality check rather than
+    // a full cmp.
+    bool needCmp = ae1->type->nextOf()->isintegral();
+    for (size_t i = 0; i < (size_t)len; i++)
+    {
+        Expression *ee1 = (*ae1->elements)[(size_t)(lo1 + i)];
+        Expression *ee2 = (*ae2->elements)[(size_t)(lo2 + i)];
+        if (needCmp)
+        {
+            sinteger_t c = ee1->toInteger() - ee2->toInteger();
+            if (c > 0)
+                return 1;
+            if (c < 0)
+                return -1;
+        }
+        else
+        {
+            if (ctfeRawCmp(loc, ee1, ee2))
+                return 1;
+        }
+    }
+    return 0;
+}
+
+/* Given a delegate expression e, return .funcptr.
+ * If e is NullExp, return NULL.
+ */
+FuncDeclaration *funcptrOf(Expression *e)
+{
+    assert(e->type->ty == Tdelegate);
+
+    if (e->op == TOKdelegate)
+        return ((DelegateExp *)e)->func;
+    if (e->op == TOKfunction)
+        return ((FuncExp *)e)->fd;
+    assert(e->op == TOKnull);
+    return NULL;
+}
+
+bool isArray(Expression *e)
+{
+    return e->op == TOKarrayliteral || e->op == TOKstring ||
+           e->op == TOKslice || e->op == TOKnull;
+}
+
+/* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
+ * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
+ */
+int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2)
+{
+    if (e1->op == TOKclassreference || e2->op == TOKclassreference)
+    {
+        if (e1->op == TOKclassreference && e2->op == TOKclassreference &&
+            ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value)
+            return 0;
+        return 1;
+    }
+    if (e1->op == TOKtypeid && e2->op == TOKtypeid)
+    {
+        // printf("e1: %s\n", e1->toChars());
+        // printf("e2: %s\n", e2->toChars());
+        Type *t1 = isType(((TypeidExp *)e1)->obj);
+        Type *t2 = isType(((TypeidExp *)e2)->obj);
+        assert(t1);
+        assert(t2);
+        return t1 != t2;
+    }
+
+    // null == null, regardless of type
+
+    if (e1->op == TOKnull && e2->op == TOKnull)
+        return 0;
+
+    if (e1->type->ty == Tpointer && e2->type->ty == Tpointer)
+    {
+        // Can only be an equality test.
+
+        dinteger_t ofs1, ofs2;
+        Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
+        Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
+        if ((agg1 == agg2) || (agg1->op == TOKvar && agg2->op == TOKvar &&
+            ((VarExp *)agg1)->var == ((VarExp *)agg2)->var))
+        {
+            if (ofs1 == ofs2)
+                return 0;
+        }
+        return 1;
+    }
+    if (e1->type->ty == Tdelegate && e2->type->ty == Tdelegate)
+    {
+        // If .funcptr isn't the same, they are not equal
+
+        if (funcptrOf(e1) != funcptrOf(e2))
+            return 1;
+
+        // If both are delegate literals, assume they have the
+        // same closure pointer. TODO: We don't support closures yet!
+        if (e1->op == TOKfunction && e2->op == TOKfunction)
+            return 0;
+        assert(e1->op == TOKdelegate && e2->op == TOKdelegate);
+
+        // Same .funcptr. Do they have the same .ptr?
+        Expression * ptr1 = ((DelegateExp *)e1)->e1;
+        Expression * ptr2 = ((DelegateExp *)e2)->e1;
+
+        dinteger_t ofs1, ofs2;
+        Expression *agg1 = getAggregateFromPointer(ptr1, &ofs1);
+        Expression *agg2 = getAggregateFromPointer(ptr2, &ofs2);
+        // If they are TOKvar, it means they are FuncDeclarations
+        if ((agg1 == agg2 && ofs1 == ofs2) ||
+            (agg1->op == TOKvar && agg2->op == TOKvar &&
+             ((VarExp *)agg1)->var == ((VarExp *)agg2)->var))
+        {
+            return 0;
+        }
+        return 1;
+    }
+    if (isArray(e1) && isArray(e2))
+    {
+        uinteger_t len1 = resolveArrayLength(e1);
+        uinteger_t len2 = resolveArrayLength(e2);
+        // workaround for dmc optimizer bug calculating wrong len for
+        // uinteger_t len = (len1 < len2 ? len1 : len2);
+        // if (len == 0) ...
+        if (len1 > 0 && len2 > 0)
+        {
+            uinteger_t len = (len1 < len2 ? len1 : len2);
+            int res = ctfeCmpArrays(loc, e1, e2, len);
+            if (res != 0)
+                return res;
+        }
+        return (int)(len1 - len2);
+    }
+    if (e1->type->isintegral())
+    {
+        return e1->toInteger() != e2->toInteger();
+    }
+    real_t r1;
+    real_t r2;
+    if (e1->type->isreal())
+    {
+        r1 = e1->toReal();
+        r2 = e2->toReal();
+        goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+        r1 = e1->toImaginary();
+        r2 = e2->toImaginary();
+     L1:
+        if (CTFloat::isNaN(r1) || CTFloat::isNaN(r2)) // if unordered
+        {
+            return 1;
+        }
+        else
+        {
+            return (r1 != r2);
+        }
+    }
+    else if (e1->type->iscomplex())
+    {
+        return e1->toComplex() != e2->toComplex();
+    }
+
+    if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
+    {
+        StructLiteralExp *es1 = (StructLiteralExp *)e1;
+        StructLiteralExp *es2 = (StructLiteralExp *)e2;
+        // For structs, we only need to return 0 or 1 (< and > aren't legal).
+
+        if (es1->sd != es2->sd)
+            return 1;
+        else if ((!es1->elements || !es1->elements->dim) &&
+            (!es2->elements || !es2->elements->dim))
+            return 0;            // both arrays are empty
+        else if (!es1->elements || !es2->elements)
+            return 1;
+        else if (es1->elements->dim != es2->elements->dim)
+            return 1;
+        else
+        {
+            for (size_t i = 0; i < es1->elements->dim; i++)
+            {
+                Expression *ee1 = (*es1->elements)[i];
+                Expression *ee2 = (*es2->elements)[i];
+
+                if (ee1 == ee2)
+                    continue;
+                if (!ee1 || !ee2)
+                   return 1;
+                int cmp = ctfeRawCmp(loc, ee1, ee2);
+                if (cmp)
+                    return 1;
+            }
+            return 0;   // All elements are equal
+        }
+    }
+    if (e1->op == TOKassocarrayliteral && e2->op == TOKassocarrayliteral)
+    {
+        AssocArrayLiteralExp *es1 = (AssocArrayLiteralExp *)e1;
+        AssocArrayLiteralExp *es2 = (AssocArrayLiteralExp *)e2;
+
+        size_t dim = es1->keys->dim;
+        if (es2->keys->dim != dim)
+            return 1;
+
+        bool *used = (bool *)mem.xmalloc(sizeof(bool) * dim);
+        memset(used, 0, sizeof(bool) * dim);
+
+        for (size_t i = 0; i < dim; ++i)
+        {
+            Expression *k1 = (*es1->keys)[i];
+            Expression *v1 = (*es1->values)[i];
+            Expression *v2 = NULL;
+            for (size_t j = 0; j < dim; ++j)
+            {
+                if (used[j])
+                    continue;
+                Expression *k2 = (*es2->keys)[j];
+
+                if (ctfeRawCmp(loc, k1, k2))
+                    continue;
+                used[j] = true;
+                v2 = (*es2->values)[j];
+                break;
+            }
+            if (!v2 || ctfeRawCmp(loc, v1, v2))
+            {
+                mem.xfree(used);
+                return 1;
+            }
+        }
+        mem.xfree(used);
+        return 0;
+    }
+    error(loc, "CTFE internal error: bad compare of `%s` and `%s`", e1->toChars(), e2->toChars());
+    assert(0);
+    return 0;
+}
+
+/// Evaluate ==, !=.  Resolves slices before comparing. Returns 0 or 1
+int ctfeEqual(Loc loc, TOK op, Expression *e1, Expression *e2)
+{
+    int cmp = !ctfeRawCmp(loc, e1, e2);
+    if (op == TOKnotequal)
+        cmp ^= 1;
+    return cmp;
+}
+
+/// Evaluate is, !is.  Resolves slices before comparing. Returns 0 or 1
+int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2)
+{
+    //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", Token::toChars(op),
+    //    Token::toChars(e1->op), e1->toChars(), Token::toChars(e2->op), e1->toChars());
+    int cmp;
+    if (e1->op == TOKnull)
+    {
+        cmp = (e2->op == TOKnull);
+    }
+    else if (e2->op == TOKnull)
+    {
+        cmp = 0;
+    }
+    else if (e1->op == TOKsymoff && e2->op == TOKsymoff)
+    {
+        SymOffExp *es1 = (SymOffExp *)e1;
+        SymOffExp *es2 = (SymOffExp *)e2;
+        cmp = (es1->var == es2->var && es1->offset == es2->offset);
+    }
+    else if (e1->type->isreal())
+        cmp = RealEquals(e1->toReal(), e2->toReal());
+    else if (e1->type->isimaginary())
+        cmp = RealEquals(e1->toImaginary(), e2->toImaginary());
+    else if (e1->type->iscomplex())
+    {
+        complex_t v1 = e1->toComplex();
+        complex_t v2 = e2->toComplex();
+        cmp = RealEquals(creall(v1), creall(v2)) &&
+                 RealEquals(cimagl(v1), cimagl(v1));
+    }
+    else
+        cmp = !ctfeRawCmp(loc, e1, e2);
+
+    if (op == TOKnotidentity || op == TOKnotequal)
+        cmp ^= 1;
+    return cmp;
+}
+
+/// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
+int ctfeCmp(Loc loc, TOK op, Expression *e1, Expression *e2)
+{
+    Type *t1 = e1->type->toBasetype();
+    Type *t2 = e2->type->toBasetype();
+
+    if (t1->isString() && t2->isString())
+        return specificCmp(op, ctfeRawCmp(loc, e1, e2));
+    else if (t1->isreal())
+        return realCmp(op, e1->toReal(), e2->toReal());
+    else if (t1->isimaginary())
+        return realCmp(op, e1->toImaginary(), e2->toImaginary());
+    else if (t1->isunsigned() || t2->isunsigned())
+        return intUnsignedCmp(op, e1->toInteger(), e2->toInteger());
+    else
+        return intSignedCmp(op, e1->toInteger(), e2->toInteger());
+}
+
+UnionExp ctfeCat(Type *type, Expression *e1, Expression *e2)
+{
+    Loc loc = e1->loc;
+    Type *t1 = e1->type->toBasetype();
+    Type *t2 = e2->type->toBasetype();
+    UnionExp ue;
+    if (e2->op == TOKstring && e1->op == TOKarrayliteral &&
+        t1->nextOf()->isintegral())
+    {
+        // [chars] ~ string => string (only valid for CTFE)
+        StringExp *es1 = (StringExp *)e2;
+        ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1;
+        size_t len = es1->len + es2->elements->dim;
+        unsigned char sz = es1->sz;
+
+        void *s = mem.xmalloc((len + 1) * sz);
+        memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz);
+        for (size_t i = 0; i < es2->elements->dim; i++)
+        {
+            Expression *es2e = (*es2->elements)[i];
+            if (es2e->op != TOKint64)
+            {
+                new(&ue) CTFEExp(TOKcantexp);
+                return ue;
+            }
+            dinteger_t v = es2e->toInteger();
+            Port::valcpy((utf8_t *)s + i * sz, v, sz);
+        }
+
+        // Add terminating 0
+        memset((utf8_t *)s + len * sz, 0, sz);
+
+        new(&ue) StringExp(loc, s, len);
+        StringExp *es = (StringExp *)ue.exp();
+        es->sz = sz;
+        es->committed = 0;
+        es->type = type;
+        return ue;
+    }
+    if (e1->op == TOKstring && e2->op == TOKarrayliteral &&
+        t2->nextOf()->isintegral())
+    {
+        // string ~ [chars] => string (only valid for CTFE)
+        // Concatenate the strings
+        StringExp *es1 = (StringExp *)e1;
+        ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+        size_t len = es1->len + es2->elements->dim;
+        unsigned char sz = es1->sz;
+
+        void *s = mem.xmalloc((len + 1) * sz);
+        memcpy(s, es1->string, es1->len * sz);
+        for (size_t i = 0; i < es2->elements->dim; i++)
+        {
+            Expression *es2e = (*es2->elements)[i];
+            if (es2e->op != TOKint64)
+            {
+                new(&ue) CTFEExp(TOKcantexp);
+                return ue;
+            }
+            dinteger_t v = es2e->toInteger();
+            Port::valcpy((utf8_t *)s + (es1->len + i) * sz, v, sz);
+        }
+
+        // Add terminating 0
+        memset((utf8_t *)s + len * sz, 0, sz);
+
+        new(&ue) StringExp(loc, s, len);
+        StringExp *es = (StringExp *)ue.exp();
+        es->sz = sz;
+        es->committed = 0; //es1->committed;
+        es->type = type;
+        return ue;
+    }
+    if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
+        t1->nextOf()->equals(t2->nextOf()))
+    {
+        //  [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
+        ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+        ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+        new(&ue) ArrayLiteralExp(es1->loc, copyLiteralArray(es1->elements));
+        es1 = (ArrayLiteralExp *)ue.exp();
+        es1->elements->insert(es1->elements->dim, copyLiteralArray(es2->elements));
+        es1->type = type;
+        return ue;
+    }
+    if (e1->op == TOKarrayliteral && e2->op == TOKnull &&
+        t1->nextOf()->equals(t2->nextOf()))
+    {
+        //  [ e1 ] ~ null ----> [ e1 ].dup
+        ue = paintTypeOntoLiteralCopy(type, copyLiteral(e1).copy());
+        return ue;
+    }
+    if (e1->op == TOKnull && e2->op == TOKarrayliteral &&
+        t1->nextOf()->equals(t2->nextOf()))
+    {
+        //  null ~ [ e2 ] ----> [ e2 ].dup
+        ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy());
+        return ue;
+    }
+    ue = Cat(type, e1, e2);
+    return ue;
+}
+
+/*  Given an AA literal 'ae', and a key 'e2':
+ *  Return ae[e2] if present, or NULL if not found.
+ */
+Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2)
+{
+    /* Search the keys backwards, in case there are duplicate keys
+     */
+    for (size_t i = ae->keys->dim; i;)
+    {
+        i--;
+        Expression *ekey = (*ae->keys)[i];
+        int eq = ctfeEqual(loc, TOKequal, ekey, e2);
+        if (eq)
+        {
+            return (*ae->values)[i];
+        }
+    }
+    return NULL;
+}
+
+/* Same as for constfold.Index, except that it only works for static arrays,
+ * dynamic arrays, and strings. We know that e1 is an
+ * interpreted CTFE expression, so it cannot have side-effects.
+ */
+Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx)
+{
+    //printf("ctfeIndex(e1 = %s)\n", e1->toChars());
+    assert(e1->type);
+    if (e1->op == TOKstring)
+    {
+        StringExp *es1 = (StringExp *)e1;
+        if (indx >= es1->len)
+        {
+            error(loc, "string index %llu is out of bounds [0 .. %llu]", indx, (ulonglong)es1->len);
+            return CTFEExp::cantexp;
+        }
+        return new IntegerExp(loc, es1->charAt(indx), type);
+    }
+    assert(e1->op == TOKarrayliteral);
+    {
+        ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+        if (indx >= ale->elements->dim)
+        {
+            error(loc, "array index %llu is out of bounds %s[0 .. %llu]", indx, e1->toChars(), (ulonglong)ale->elements->dim);
+            return CTFEExp::cantexp;
+        }
+        Expression *e = (*ale->elements)[(size_t)indx];
+        return paintTypeOntoLiteral(type, e);
+    }
+}
+
+Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e)
+{
+    if (e->op == TOKnull)
+        return paintTypeOntoLiteral(to, e);
+    if (e->op == TOKclassreference)
+    {
+        // Disallow reinterpreting class casts. Do this by ensuring that
+        // the original class can implicitly convert to the target class
+        ClassDeclaration *originalClass = ((ClassReferenceExp *)e)->originalClass();
+        if (originalClass->type->implicitConvTo(to->mutableOf()))
+            return paintTypeOntoLiteral(to, e);
+        else
+            return new NullExp(loc, to);
+    }
+    // Allow TypeInfo type painting
+    if (isTypeInfo_Class(e->type) && e->type->implicitConvTo(to))
+        return paintTypeOntoLiteral(to, e);
+    // Allow casting away const for struct literals
+    if (e->op == TOKstructliteral &&
+        e->type->toBasetype()->castMod(0) == to->toBasetype()->castMod(0))
+    {
+        return paintTypeOntoLiteral(to, e);
+    }
+
+    Expression *r;
+    if (e->type->equals(type) && type->equals(to))
+    {
+        // necessary not to change e's address for pointer comparisons
+        r = e;
+    }
+    else if (to->toBasetype()->ty == Tarray &&     type->toBasetype()->ty == Tarray &&
+             to->toBasetype()->nextOf()->size() == type->toBasetype()->nextOf()->size())
+    {
+        // Bugzilla 12495: Array reinterpret casts: eg. string to immutable(ubyte)[]
+        return paintTypeOntoLiteral(to, e);
+    }
+    else
+    {
+        r = Cast(type, to, e).copy();
+    }
+    if (CTFEExp::isCantExp(r))
+        error(loc, "cannot cast %s to %s at compile time", e->toChars(), to->toChars());
+    if (e->op == TOKarrayliteral)
+        ((ArrayLiteralExp *)e)->ownedByCtfe = OWNEDctfe;
+    if (e->op == TOKstring)
+        ((StringExp *)e)->ownedByCtfe = OWNEDctfe;
+    return r;
+}
+
+/******** Assignment helper functions ***************************/
+
+/* Set dest = src, where both dest and src are container value literals
+ * (ie, struct literals, or static arrays (can be an array literal or a string))
+ * Assignment is recursively in-place.
+ * Purpose: any reference to a member of 'dest' will remain valid after the
+ * assignment.
+ */
+void assignInPlace(Expression *dest, Expression *src)
+{
+    assert(dest->op == TOKstructliteral ||
+           dest->op == TOKarrayliteral ||
+           dest->op == TOKstring);
+    Expressions *oldelems;
+    Expressions *newelems;
+    if (dest->op == TOKstructliteral)
+    {
+        assert(dest->op == src->op);
+        oldelems = ((StructLiteralExp *)dest)->elements;
+        newelems = ((StructLiteralExp *)src)->elements;
+        if (((StructLiteralExp *)dest)->sd->isNested() && oldelems->dim == newelems->dim - 1)
+            oldelems->push(NULL);
+    }
+    else if (dest->op == TOKarrayliteral && src->op==TOKarrayliteral)
+    {
+        oldelems = ((ArrayLiteralExp *)dest)->elements;
+        newelems = ((ArrayLiteralExp *)src)->elements;
+    }
+    else if (dest->op == TOKstring && src->op == TOKstring)
+    {
+        sliceAssignStringFromString((StringExp *)dest, (StringExp *)src, 0);
+        return;
+    }
+    else if (dest->op == TOKarrayliteral && src->op == TOKstring)
+    {
+        sliceAssignArrayLiteralFromString((ArrayLiteralExp *)dest, (StringExp *)src, 0);
+        return;
+    }
+    else if (src->op == TOKarrayliteral && dest->op == TOKstring)
+    {
+        sliceAssignStringFromArrayLiteral((StringExp *)dest, (ArrayLiteralExp *)src, 0);
+        return;
+    }
+    else
+        assert(0);
+
+    assert(oldelems->dim == newelems->dim);
+
+    for (size_t i= 0; i < oldelems->dim; ++i)
+    {
+        Expression *e = (*newelems)[i];
+        Expression *o = (*oldelems)[i];
+        if (e->op == TOKstructliteral)
+        {
+            assert(o->op == e->op);
+            assignInPlace(o, e);
+        }
+        else if (e->type->ty == Tsarray && e->op != TOKvoid &&
+                 o->type->ty == Tsarray)
+        {
+            assignInPlace(o, e);
+        }
+        else
+        {
+            (*oldelems)[i] = (*newelems)[i];
+        }
+    }
+}
+
+// Duplicate the elements array, then set field 'indexToChange' = newelem.
+Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem)
+{
+    Expressions *expsx = new Expressions();
+    ++CtfeStatus::numArrayAllocs;
+    expsx->setDim(oldelems->dim);
+    for (size_t j = 0; j < expsx->dim; j++)
+    {
+        if (j == indexToChange)
+            (*expsx)[j] = newelem;
+        else
+            (*expsx)[j] = (*oldelems)[j];
+    }
+    return expsx;
+}
+
+// Create a new struct literal, which is the same as se except that se.field[offset] = elem
+Expression *modifyStructField(Type *type, StructLiteralExp *se, size_t offset, Expression *newval)
+{
+    int fieldi = se->getFieldIndex(newval->type, (unsigned)offset);
+    if (fieldi == -1)
+        return CTFEExp::cantexp;
+    /* Create new struct literal reflecting updated fieldi
+    */
+    Expressions *expsx = changeOneElement(se->elements, fieldi, newval);
+    StructLiteralExp * ee = new StructLiteralExp(se->loc, se->sd, expsx);
+    ee->type = se->type;
+    ee->ownedByCtfe = OWNEDctfe;
+    return ee;
+}
+
+// Given an AA literal aae,  set aae[index] = newval and return newval.
+Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae,
+    Expression *index, Expression *newval)
+{
+    /* Create new associative array literal reflecting updated key/value
+     */
+    Expressions *keysx = aae->keys;
+    Expressions *valuesx = aae->values;
+    int updated = 0;
+    for (size_t j = valuesx->dim; j; )
+    {
+        j--;
+        Expression *ekey = (*aae->keys)[j];
+        int eq = ctfeEqual(loc, TOKequal, ekey, index);
+        if (eq)
+        {
+            (*valuesx)[j] = newval;
+            updated = 1;
+        }
+    }
+    if (!updated)
+    {
+        // Append index/newval to keysx[]/valuesx[]
+        valuesx->push(newval);
+        keysx->push(index);
+    }
+    return newval;
+}
+
+/// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
+/// oldlen, change its length to newlen. If the newlen is longer than oldlen,
+/// all new elements will be set to the default initializer for the element type.
+UnionExp changeArrayLiteralLength(Loc loc, TypeArray *arrayType,
+    Expression *oldval,  size_t oldlen, size_t newlen)
+{
+    UnionExp ue;
+    Type *elemType = arrayType->next;
+    assert(elemType);
+    Expression *defaultElem = elemType->defaultInitLiteral(loc);
+    Expressions *elements = new Expressions();
+    elements->setDim(newlen);
+
+    // Resolve slices
+    size_t indxlo = 0;
+    if (oldval->op == TOKslice)
+    {
+        indxlo = (size_t)((SliceExp *)oldval)->lwr->toInteger();
+        oldval = ((SliceExp *)oldval)->e1;
+    }
+    size_t copylen = oldlen < newlen ? oldlen : newlen;
+    if (oldval->op == TOKstring)
+    {
+        StringExp *oldse = (StringExp *)oldval;
+        void *s = mem.xcalloc(newlen + 1, oldse->sz);
+        memcpy(s, oldse->string, copylen * oldse->sz);
+        unsigned defaultValue = (unsigned)(defaultElem->toInteger());
+        for (size_t elemi = copylen; elemi < newlen; ++elemi)
+        {
+            switch (oldse->sz)
+            {
+                case 1:     (( utf8_t *)s)[(size_t)(indxlo + elemi)] = ( utf8_t)defaultValue;  break;
+                case 2:     ((utf16_t *)s)[(size_t)(indxlo + elemi)] = (utf16_t)defaultValue;  break;
+                case 4:     ((utf32_t *)s)[(size_t)(indxlo + elemi)] = (utf32_t)defaultValue;  break;
+                default:    assert(0);
+            }
+        }
+        new(&ue) StringExp(loc, s, newlen);
+        StringExp *se = (StringExp *)ue.exp();
+        se->type = arrayType;
+        se->sz = oldse->sz;
+        se->committed = oldse->committed;
+        se->ownedByCtfe = OWNEDctfe;
+    }
+    else
+    {
+        if (oldlen != 0)
+        {
+            assert(oldval->op == TOKarrayliteral);
+            ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval;
+            for (size_t i = 0; i < copylen; i++)
+                (*elements)[i] = (*ae->elements)[indxlo + i];
+        }
+        if (elemType->ty == Tstruct || elemType->ty == Tsarray)
+        {
+            /* If it is an aggregate literal representing a value type,
+             * we need to create a unique copy for each element
+             */
+            for (size_t i = copylen; i < newlen; i++)
+                (*elements)[i] = copyLiteral(defaultElem).copy();
+        }
+        else
+        {
+            for (size_t i = copylen; i < newlen; i++)
+                (*elements)[i] = defaultElem;
+        }
+        new(&ue) ArrayLiteralExp(loc, elements);
+        ArrayLiteralExp *aae = (ArrayLiteralExp *)ue.exp();
+        aae->type = arrayType;
+        aae->ownedByCtfe = OWNEDctfe;
+    }
+    return ue;
+}
+
+/*************************** CTFE Sanity Checks ***************************/
+
+bool isCtfeValueValid(Expression *newval)
+{
+    Type *tb = newval->type->toBasetype();
+
+    if (newval->op == TOKint64 ||
+        newval->op == TOKfloat64 ||
+        newval->op == TOKchar ||
+        newval->op == TOKcomplex80)
+    {
+        return tb->isscalar();
+    }
+    if (newval->op == TOKnull)
+    {
+        return tb->ty == Tnull ||
+               tb->ty == Tpointer ||
+               tb->ty == Tarray ||
+               tb->ty == Taarray ||
+               tb->ty == Tclass ||
+               tb->ty == Tdelegate;
+    }
+
+    if (newval->op == TOKstring)
+        return true;    // CTFE would directly use the StringExp in AST.
+    if (newval->op == TOKarrayliteral)
+        return true;    //((ArrayLiteralExp *)newval)->ownedByCtfe;
+    if (newval->op == TOKassocarrayliteral)
+        return true;    //((AssocArrayLiteralExp *)newval)->ownedByCtfe;
+    if (newval->op == TOKstructliteral)
+        return true;    //((StructLiteralExp *)newval)->ownedByCtfe;
+    if (newval->op == TOKclassreference)
+        return true;
+
+    if (newval->op == TOKvector)
+        return true;    // vector literal
+
+    if (newval->op == TOKfunction)
+        return true;    // function literal or delegate literal
+    if (newval->op == TOKdelegate)
+    {
+        // &struct.func or &clasinst.func
+        // &nestedfunc
+        Expression *ethis = ((DelegateExp *)newval)->e1;
+        return (ethis->op == TOKstructliteral ||
+                ethis->op == TOKclassreference ||
+                ethis->op == TOKvar && ((VarExp *)ethis)->var == ((DelegateExp *)newval)->func);
+    }
+    if (newval->op == TOKsymoff)
+    {
+        // function pointer, or pointer to static variable
+        Declaration *d = ((SymOffExp *)newval)->var;
+        return d->isFuncDeclaration() || d->isDataseg();
+    }
+    if (newval->op == TOKtypeid)
+    {
+        // always valid
+        return true;
+    }
+    if (newval->op == TOKaddress)
+    {
+        // e1 should be a CTFE reference
+        Expression *e1 = ((AddrExp *)newval)->e1;
+        return tb->ty == Tpointer &&
+               (e1->op == TOKstructliteral && isCtfeValueValid(e1) ||
+                e1->op == TOKvar ||
+                e1->op == TOKdotvar && isCtfeReferenceValid(e1) ||
+                e1->op == TOKindex && isCtfeReferenceValid(e1) ||
+                e1->op == TOKslice && e1->type->toBasetype()->ty == Tsarray);
+    }
+    if (newval->op == TOKslice)
+    {
+        // e1 should be an array aggregate
+        SliceExp *se = (SliceExp *)newval;
+        assert(se->lwr && se->lwr->op == TOKint64);
+        assert(se->upr && se->upr->op == TOKint64);
+        return (tb->ty == Tarray ||
+                tb->ty == Tsarray) &&
+               (se->e1->op == TOKstring ||
+                se->e1->op == TOKarrayliteral);
+    }
+
+    if (newval->op == TOKvoid)
+        return true;    // uninitialized value
+
+    newval->error("CTFE internal error: illegal CTFE value %s", newval->toChars());
+    return false;
+}
+
+bool isCtfeReferenceValid(Expression *newval)
+{
+    if (newval->op == TOKthis)
+        return true;
+    if (newval->op == TOKvar)
+    {
+        VarDeclaration *v = ((VarExp *)newval)->var->isVarDeclaration();
+        assert(v);
+        // Must not be a reference to a reference
+        return true;
+    }
+    if (newval->op == TOKindex)
+    {
+        Expression *eagg = ((IndexExp *)newval)->e1;
+        return eagg->op == TOKstring ||
+               eagg->op == TOKarrayliteral ||
+               eagg->op == TOKassocarrayliteral;
+    }
+    if (newval->op == TOKdotvar)
+    {
+        Expression *eagg = ((DotVarExp *)newval)->e1;
+        return  (eagg->op == TOKstructliteral || eagg->op == TOKclassreference) &&
+                isCtfeValueValid(eagg);
+    }
+
+    // Internally a ref variable may directly point a stack memory.
+    // e.g. ref int v = 1;
+    return isCtfeValueValid(newval);
+}
+
+// Used for debugging only
+void showCtfeExpr(Expression *e, int level)
+{
+    for (int i = level; i > 0; --i) printf(" ");
+    Expressions *elements = NULL;
+    // We need the struct definition to detect block assignment
+    StructDeclaration *sd = NULL;
+    ClassDeclaration *cd = NULL;
+    if (e->op == TOKstructliteral)
+    {
+        elements = ((StructLiteralExp *)e)->elements;
+        sd = ((StructLiteralExp *)e)->sd;
+        printf("STRUCT type = %s %p:\n", e->type->toChars(),
+            e);
+    }
+    else if (e->op == TOKclassreference)
+    {
+        elements = ((ClassReferenceExp *)e)->value->elements;
+        cd = ((ClassReferenceExp *)e)->originalClass();
+        printf("CLASS type = %s %p:\n", e->type->toChars(),
+            ((ClassReferenceExp *)e)->value);
+    }
+    else if (e->op == TOKarrayliteral)
+    {
+        elements = ((ArrayLiteralExp *)e)->elements;
+        printf("ARRAY LITERAL type=%s %p:\n", e->type->toChars(),
+            e);
+    }
+    else if (e->op == TOKassocarrayliteral)
+    {
+        printf("AA LITERAL type=%s %p:\n", e->type->toChars(),
+            e);
+    }
+    else if (e->op == TOKstring)
+    {
+        printf("STRING %s %p\n", e->toChars(),
+            ((StringExp *)e)->string);
+    }
+    else if (e->op == TOKslice)
+    {
+        printf("SLICE %p: %s\n", e, e->toChars());
+        showCtfeExpr(((SliceExp *)e)->e1, level + 1);
+    }
+    else if (e->op == TOKvar)
+    {
+        printf("VAR %p %s\n", e, e->toChars());
+        VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
+        if (v && getValue(v))
+            showCtfeExpr(getValue(v), level + 1);
+    }
+    else if (e->op == TOKaddress)
+    {
+        // This is potentially recursive. We mustn't try to print the thing we're pointing to.
+        printf("POINTER %p to %p: %s\n", e, ((AddrExp *)e)->e1, e->toChars());
+    }
+    else
+        printf("VALUE %p: %s\n", e, e->toChars());
+
+    if (elements)
+    {
+        size_t fieldsSoFar = 0;
+        for (size_t i = 0; i < elements->dim; i++)
+        {
+            Expression *z = NULL;
+            VarDeclaration *v = NULL;
+            if (i > 15)
+            {
+                printf("...(total %d elements)\n", (int)elements->dim);
+                return;
+            }
+            if (sd)
+            {
+                v = sd->fields[i];
+                z = (*elements)[i];
+            }
+            else if (cd)
+            {
+                while (i - fieldsSoFar >= cd->fields.dim)
+                {
+                    fieldsSoFar += cd->fields.dim;
+                    cd = cd->baseClass;
+                    for (int j = level; j > 0; --j) printf(" ");
+                    printf(" BASE CLASS: %s\n", cd->toChars());
+                }
+                v = cd->fields[i - fieldsSoFar];
+                assert((elements->dim + i) >= (fieldsSoFar + cd->fields.dim));
+                size_t indx = (elements->dim - fieldsSoFar)- cd->fields.dim + i;
+                assert(indx < elements->dim);
+                z = (*elements)[indx];
+            }
+            if (!z)
+            {
+                for (int j = level; j > 0; --j) printf(" ");
+                printf(" void\n");
+                continue;
+            }
+
+            if (v)
+            {
+                // If it is a void assignment, use the default initializer
+                if ((v->type->ty != z->type->ty) && v->type->ty == Tsarray)
+                {
+                    for (int j = level; --j; ) printf(" ");
+                    printf(" field: block initalized static array\n");
+                    continue;
+                }
+            }
+            showCtfeExpr(z, level + 1);
+        }
+    }
+}
+
+/*************************** Void initialization ***************************/
+
+UnionExp voidInitLiteral(Type *t, VarDeclaration *var)
+{
+    UnionExp ue;
+    if (t->ty == Tsarray)
+    {
+        TypeSArray *tsa = (TypeSArray *)t;
+        Expression *elem = voidInitLiteral(tsa->next, var).copy();
+
+        // For aggregate value types (structs, static arrays) we must
+        // create an a separate copy for each element.
+        bool mustCopy = (elem->op == TOKarrayliteral || elem->op == TOKstructliteral);
+
+        Expressions *elements = new Expressions();
+        size_t d = (size_t)tsa->dim->toInteger();
+        elements->setDim(d);
+        for (size_t i = 0; i < d; i++)
+        {
+            if (mustCopy && i > 0)
+                elem  = copyLiteral(elem).copy();
+            (*elements)[i] = elem;
+        }
+        new(&ue) ArrayLiteralExp(var->loc, elements);
+        ArrayLiteralExp *ae = (ArrayLiteralExp *)ue.exp();
+        ae->type = tsa;
+        ae->ownedByCtfe = OWNEDctfe;
+    }
+    else if (t->ty == Tstruct)
+    {
+        TypeStruct *ts = (TypeStruct *)t;
+        Expressions *exps = new Expressions();
+        exps->setDim(ts->sym->fields.dim);
+        for (size_t i = 0; i < ts->sym->fields.dim; i++)
+        {
+            (*exps)[i] = voidInitLiteral(ts->sym->fields[i]->type, ts->sym->fields[i]).copy();
+        }
+        new(&ue) StructLiteralExp(var->loc, ts->sym, exps);
+        StructLiteralExp *se = (StructLiteralExp *)ue.exp();
+        se->type = ts;
+        se->ownedByCtfe = OWNEDctfe;
+    }
+    else
+        new(&ue) VoidInitExp(var, t);
+    return ue;
+}
diff --git a/gcc/d/dfrontend/ctfloat.h b/gcc/d/dfrontend/ctfloat.h
new file mode 100644
index 00000000000..ca20502c537
--- /dev/null
+++ b/gcc/d/dfrontend/ctfloat.h
@@ -0,0 +1,51 @@
+
+/* Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/dlang/dmd/blob/master/src/root/ctfloat.h
+ */
+
+#ifndef CTFLOAT_H
+#define CTFLOAT_H
+
+#include "longdouble.h"
+
+// Type used by the front-end for compile-time reals
+typedef longdouble real_t;
+
+// Compile-time floating-point helper
+struct CTFloat
+{
+    static bool yl2x_supported;
+    static bool yl2xp1_supported;
+
+    static void yl2x(const real_t *x, const real_t *y, real_t *res);
+    static void yl2xp1(const real_t *x, const real_t *y, real_t *res);
+
+    static real_t sin(real_t x);
+    static real_t cos(real_t x);
+    static real_t tan(real_t x);
+    static real_t sqrt(real_t x);
+    static real_t fabs(real_t x);
+    static real_t ldexp(real_t n, int exp);
+
+    static bool isIdentical(real_t a, real_t b);
+    static bool isNaN(real_t r);
+    static bool isSNaN(real_t r);
+    static bool isInfinity(real_t r);
+
+    static real_t parse(const char *literal, bool *isOutOfRange = NULL);
+    static int sprint(char *str, char fmt, real_t x);
+
+    static size_t hash(real_t a);
+
+    // Constant real values 0, 1, -1 and 0.5.
+    static real_t zero;
+    static real_t one;
+    static real_t minusone;
+    static real_t half;
+};
+
+#endif
diff --git a/gcc/d/dfrontend/dcast.c b/gcc/d/dfrontend/dcast.c
new file mode 100644
index 00000000000..31d1e4a80fd
--- /dev/null
+++ b/gcc/d/dfrontend/dcast.c
@@ -0,0 +1,3841 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/cast.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>                     // mem{set|cpy}()
+
+#include "rmem.h"
+
+#include "expression.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "template.h"
+#include "scope.h"
+#include "id.h"
+#include "init.h"
+#include "tokens.h"
+
+FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
+bool isCommutative(TOK op);
+MOD MODmerge(MOD mod1, MOD mod2);
+Expression *semantic(Expression *e, Scope *sc);
+
+/* ==================== implicitCast ====================== */
+
+/**************************************
+ * Do an implicit cast.
+ * Issue error if it can't be done.
+ */
+
+
+Expression *implicitCastTo(Expression *e, Scope *sc, Type *t)
+{
+    class ImplicitCastTo : public Visitor
+    {
+    public:
+        Type *t;
+        Scope *sc;
+        Expression *result;
+
+        ImplicitCastTo(Scope *sc, Type *t)
+            : sc(sc), t(t)
+        {
+            result = NULL;
+        }
+
+        void visit(Expression *e)
+        {
+            //printf("Expression::implicitCastTo(%s of type %s) => %s\n", e->toChars(), e->type->toChars(), t->toChars());
+
+            MATCH match = e->implicitConvTo(t);
+            if (match)
+            {
+                if (match == MATCHconst &&
+                    (e->type->constConv(t) ||
+                     !e->isLvalue() && e->type->equivalent(t)))
+                {
+                    /* Do not emit CastExp for const conversions and
+                     * unique conversions on rvalue.
+                     */
+                    result = e->copy();
+                    result->type = t;
+                    return;
+                }
+                result = e->castTo(sc, t);
+                return;
+            }
+
+            result = e->optimize(WANTvalue);
+            if (result != e)
+            {
+                result->accept(this);
+                return;
+            }
+
+            if (t->ty != Terror && e->type->ty != Terror)
+            {
+                if (!t->deco)
+                {
+                    e->error("forward reference to type %s", t->toChars());
+                }
+                else
+                {
+                    //printf("type %p ty %d deco %p\n", type, type->ty, type->deco);
+                    //type = type->semantic(loc, sc);
+                    //printf("type %s t %s\n", type->deco, t->deco);
+                    e->error("cannot implicitly convert expression (%s) of type %s to %s",
+                        e->toChars(), e->type->toChars(), t->toChars());
+                }
+            }
+            result = new ErrorExp();
+        }
+
+        void visit(StringExp *e)
+        {
+            //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e->toChars(), e->type->toChars(), t->toChars());
+            visit((Expression *)e);
+            if (result->op == TOKstring)
+            {
+                // Retain polysemous nature if it started out that way
+                ((StringExp *)result)->committed = e->committed;
+            }
+        }
+
+        void visit(ErrorExp *e)
+        {
+            result = e;
+        }
+
+        void visit(FuncExp *e)
+        {
+            //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e->type, e->type ? e->type->toChars() : NULL, t->toChars());
+            FuncExp *fe;
+            if (e->matchType(t, sc, &fe) > MATCHnomatch)
+            {
+                result = fe;
+                return;
+            }
+            visit((Expression *)e);
+        }
+
+        void visit(ArrayLiteralExp *e)
+        {
+            visit((Expression *)e);
+
+            Type *tb = result->type->toBasetype();
+            if (tb->ty == Tarray)
+                semanticTypeInfo(sc, ((TypeDArray *)tb)->next);
+        }
+
+        void visit(SliceExp *e)
+        {
+            visit((Expression *)e);
+            if (result->op != TOKslice)
+                return;
+
+            e = (SliceExp *)result;
+            if (e->e1->op == TOKarrayliteral)
+            {
+                ArrayLiteralExp *ale = (ArrayLiteralExp *)e->e1;
+                Type *tb = t->toBasetype();
+                Type *tx;
+                if (tb->ty == Tsarray)
+                    tx = tb->nextOf()->sarrayOf(ale->elements ? ale->elements->dim : 0);
+                else
+                    tx = tb->nextOf()->arrayOf();
+                e->e1 = ale->implicitCastTo(sc, tx);
+            }
+        }
+    };
+
+    ImplicitCastTo v(sc, t);
+    e->accept(&v);
+    return v.result;
+}
+
+/*******************************************
+ * Return MATCH level of implicitly converting e to type t.
+ * Don't do the actual cast; don't change e.
+ */
+
+MATCH implicitConvTo(Expression *e, Type *t)
+{
+    class ImplicitConvTo : public Visitor
+    {
+    public:
+        Type *t;
+        MATCH result;
+
+        ImplicitConvTo(Type *t)
+            : t(t)
+        {
+            result = MATCHnomatch;
+        }
+
+        void visit(Expression *e)
+        {
+        #if 0
+            printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            //static int nest; if (++nest == 10) halt();
+            if (t == Type::terror)
+                return;
+            if (!e->type)
+            {
+                e->error("%s is not an expression", e->toChars());
+                e->type = Type::terror;
+            }
+            Expression *ex = e->optimize(WANTvalue);
+            if (ex->type->equals(t))
+            {
+                result = MATCHexact;
+                return;
+            }
+            if (ex != e)
+            {
+                //printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars());
+                result = ex->implicitConvTo(t);
+                return;
+            }
+            MATCH match = e->type->implicitConvTo(t);
+            if (match != MATCHnomatch)
+            {
+                result = match;
+                return;
+            }
+
+            /* See if we can do integral narrowing conversions
+             */
+            if (e->type->isintegral() && t->isintegral() &&
+                e->type->isTypeBasic() && t->isTypeBasic())
+            {
+                IntRange src = getIntRange(e);
+                IntRange target = IntRange::fromType(t);
+                if (target.contains(src))
+                {
+                    result = MATCHconvert;
+                    return;
+                }
+            }
+        }
+
+        /******
+         * Given expression e of type t, see if we can implicitly convert e
+         * to type tprime, where tprime is type t with mod bits added.
+         * Returns:
+         *      match level
+         */
+        static MATCH implicitMod(Expression *e, Type *t, MOD mod)
+        {
+            Type *tprime;
+            if (t->ty == Tpointer)
+                tprime = t->nextOf()->castMod(mod)->pointerTo();
+            else if (t->ty == Tarray)
+                tprime = t->nextOf()->castMod(mod)->arrayOf();
+            else if (t->ty == Tsarray)
+                tprime = t->nextOf()->castMod(mod)->sarrayOf(t->size() / t->nextOf()->size());
+            else
+                tprime = t->castMod(mod);
+
+            return e->implicitConvTo(tprime);
+        }
+
+        static MATCH implicitConvToAddMin(BinExp *e, Type *t)
+        {
+            /* Is this (ptr +- offset)? If so, then ask ptr
+             * if the conversion can be done.
+             * This is to support doing things like implicitly converting a mutable unique
+             * pointer to an immutable pointer.
+             */
+
+            Type *typeb = e->type->toBasetype();
+            Type *tb = t->toBasetype();
+            if (typeb->ty != Tpointer || tb->ty != Tpointer)
+                return MATCHnomatch;
+
+            Type *t1b = e->e1->type->toBasetype();
+            Type *t2b = e->e2->type->toBasetype();
+            if (t1b->ty == Tpointer && t2b->isintegral() &&
+                t1b->equivalent(tb))
+            {
+                // ptr + offset
+                // ptr - offset
+                MATCH m = e->e1->implicitConvTo(t);
+                return (m > MATCHconst) ? MATCHconst : m;
+            }
+            if (t2b->ty == Tpointer && t1b->isintegral() &&
+                t2b->equivalent(tb))
+            {
+                // offset + ptr
+                MATCH m = e->e2->implicitConvTo(t);
+                return (m > MATCHconst) ? MATCHconst : m;
+            }
+
+            return MATCHnomatch;
+        }
+
+        void visit(AddExp *e)
+        {
+        #if 0
+            printf("AddExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            visit((Expression *)e);
+            if (result == MATCHnomatch)
+                result = implicitConvToAddMin(e, t);
+        }
+
+        void visit(MinExp *e)
+        {
+        #if 0
+            printf("MinExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            visit((Expression *)e);
+            if (result == MATCHnomatch)
+                result = implicitConvToAddMin(e, t);
+        }
+
+        void visit(IntegerExp *e)
+        {
+        #if 0
+            printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            MATCH m = e->type->implicitConvTo(t);
+            if (m >= MATCHconst)
+            {
+                result = m;
+                return;
+            }
+
+            TY ty = e->type->toBasetype()->ty;
+            TY toty = t->toBasetype()->ty;
+            TY oldty = ty;
+
+            if (m == MATCHnomatch && t->ty == Tenum)
+                return;
+
+            if (t->ty == Tvector)
+            {
+                TypeVector *tv = (TypeVector *)t;
+                TypeBasic *tb = tv->elementType();
+                if (tb->ty == Tvoid)
+                    return;
+                toty = tb->ty;
+            }
+
+            switch (ty)
+            {
+                case Tbool:
+                case Tint8:
+                case Tchar:
+                case Tuns8:
+                case Tint16:
+                case Tuns16:
+                case Twchar:
+                    ty = Tint32;
+                    break;
+
+                case Tdchar:
+                    ty = Tuns32;
+                    break;
+
+                default:
+                    break;
+            }
+
+            // Only allow conversion if no change in value
+            dinteger_t value = e->toInteger();
+            switch (toty)
+            {
+                case Tbool:
+                    if ((value & 1) != value)
+                        return;
+                    break;
+
+                case Tint8:
+                    if (ty == Tuns64 && value & ~0x7FUL)
+                        return;
+                    else if ((signed char)value != value)
+                        return;
+                    break;
+
+                case Tchar:
+                    if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F)
+                        return;
+                case Tuns8:
+                    //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value);
+                    if ((unsigned char)value != value)
+                        return;
+                    break;
+
+                case Tint16:
+                    if (ty == Tuns64 && value & ~0x7FFFUL)
+                        return;
+                    else if ((short)value != value)
+                        return;
+                    break;
+
+                case Twchar:
+                    if (oldty == Tdchar && value > 0xD7FF && value < 0xE000)
+                        return;
+                case Tuns16:
+                    if ((unsigned short)value != value)
+                        return;
+                    break;
+
+                case Tint32:
+                    if (ty == Tuns32)
+                    {
+                    }
+                    else if (ty == Tuns64 && value & ~0x7FFFFFFFUL)
+                        return;
+                    else if ((int)value != value)
+                        return;
+                    break;
+
+                case Tuns32:
+                    if (ty == Tint32)
+                    {
+                    }
+                    else if ((unsigned)value != value)
+                        return;
+                    break;
+
+                case Tdchar:
+                    if (value > 0x10FFFFUL)
+                        return;
+                    break;
+
+                case Tfloat32:
+                {
+                    volatile float f;
+                    if (e->type->isunsigned())
+                    {
+                        f = (float)value;
+                        if (f != value)
+                            return;
+                    }
+                    else
+                    {
+                        f = (float)(sinteger_t)value;
+                        if (f != (sinteger_t)value)
+                            return;
+                    }
+                    break;
+                }
+
+                case Tfloat64:
+                {
+                    volatile double f;
+                    if (e->type->isunsigned())
+                    {
+                        f = (double)value;
+                        if (f != value)
+                            return;
+                    }
+                    else
+                    {
+                        f = (double)(sinteger_t)value;
+                        if (f != (sinteger_t)value)
+                            return;
+                    }
+                    break;
+                }
+
+                case Tfloat80:
+                {
+                    volatile_longdouble f;
+                    if (e->type->isunsigned())
+                    {
+                        f = ldouble(value);
+                        if ((dinteger_t)f != value) // isn't this a noop, because the compiler prefers ld
+                            return;
+                    }
+                    else
+                    {
+                        f = ldouble((sinteger_t)value);
+                        if ((sinteger_t)f != (sinteger_t)value)
+                            return;
+                    }
+                    break;
+                }
+
+                case Tpointer:
+                    //printf("type = %s\n", type->toBasetype()->toChars());
+                    //printf("t = %s\n", t->toBasetype()->toChars());
+                    if (ty == Tpointer &&
+                        e->type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty)
+                    {
+                        /* Allow things like:
+                         *      const char* P = cast(char *)3;
+                         *      char* q = P;
+                         */
+                        break;
+                    }
+
+                default:
+                    visit((Expression *)e);
+                return;
+            }
+
+            //printf("MATCHconvert\n");
+            result = MATCHconvert;
+        }
+
+        void visit(ErrorExp *e)
+        {
+            // no match
+        }
+
+        void visit(NullExp *e)
+        {
+        #if 0
+            printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n",
+                e->toChars(), e->type->toChars(), t->toChars(), e->committed);
+        #endif
+            if (e->type->equals(t))
+            {
+                result = MATCHexact;
+                return;
+            }
+
+            /* Allow implicit conversions from immutable to mutable|const,
+             * and mutable to immutable. It works because, after all, a null
+             * doesn't actually point to anything.
+             */
+            if (t->equivalent(e->type))
+            {
+                result = MATCHconst;
+                return;
+            }
+
+            visit((Expression *)e);
+        }
+
+        void visit(StructLiteralExp *e)
+        {
+        #if 0
+            printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            visit((Expression *)e);
+            if (result != MATCHnomatch)
+                return;
+            if (e->type->ty == t->ty && e->type->ty == Tstruct &&
+                ((TypeStruct *)e->type)->sym == ((TypeStruct *)t)->sym)
+            {
+                result = MATCHconst;
+                for (size_t i = 0; i < e->elements->dim; i++)
+                {
+                    Expression *el = (*e->elements)[i];
+                    if (!el)
+                        continue;
+                    Type *te = el->type;
+                    te = e->sd->fields[i]->type->addMod(t->mod);
+                    MATCH m2 = el->implicitConvTo(te);
+                    //printf("\t%s => %s, match = %d\n", el->toChars(), te->toChars(), m2);
+                    if (m2 < result)
+                        result = m2;
+                }
+            }
+        }
+
+        void visit(StringExp *e)
+        {
+        #if 0
+            printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n",
+                e->toChars(), e->committed, e->type->toChars(), t->toChars());
+        #endif
+            if (!e->committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
+                return;
+
+            if (e->type->ty == Tsarray || e->type->ty == Tarray || e->type->ty == Tpointer)
+            {
+                TY tyn = e->type->nextOf()->ty;
+                if (tyn == Tchar || tyn == Twchar || tyn == Tdchar)
+                {
+                    switch (t->ty)
+                    {
+                        case Tsarray:
+                            if (e->type->ty == Tsarray)
+                            {
+                                TY tynto = t->nextOf()->ty;
+                                if (tynto == tyn)
+                                {
+                                    if (((TypeSArray *)e->type)->dim->toInteger() ==
+                                        ((TypeSArray *)t)->dim->toInteger())
+                                    {
+                                        result = MATCHexact;
+                                    }
+                                    return;
+                                }
+                                if (tynto == Tchar || tynto == Twchar || tynto == Tdchar)
+                                {
+                                    if (e->committed && tynto != tyn)
+                                        return;
+                                    size_t fromlen = e->numberOfCodeUnits(tynto);
+                                    size_t tolen = (size_t)((TypeSArray *)t)->dim->toInteger();
+                                    if (tolen < fromlen)
+                                        return;
+                                    if (tolen != fromlen)
+                                    {
+                                        // implicit length extending
+                                        result = MATCHconvert;
+                                        return;
+                                    }
+                                }
+                                if (!e->committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar))
+                                {
+                                    result = MATCHexact;
+                                    return;
+                                }
+                            }
+                            else if (e->type->ty == Tarray)
+                            {
+                                TY tynto = t->nextOf()->ty;
+                                if (tynto == Tchar || tynto == Twchar || tynto == Tdchar)
+                                {
+                                    if (e->committed && tynto != tyn)
+                                        return;
+                                    size_t fromlen = e->numberOfCodeUnits(tynto);
+                                    size_t tolen = (size_t)((TypeSArray *)t)->dim->toInteger();
+                                    if (tolen < fromlen)
+                                        return;
+                                    if (tolen != fromlen)
+                                    {
+                                        // implicit length extending
+                                        result = MATCHconvert;
+                                        return;
+                                    }
+                                }
+                                if (tynto == tyn)
+                                {
+                                    result = MATCHexact;
+                                    return;
+                                }
+                                if (!e->committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar))
+                                {
+                                    result = MATCHexact;
+                                    return;
+                                }
+                            }
+                            /* fall through */
+                        case Tarray:
+                        case Tpointer:
+                            Type *tn = t->nextOf();
+                            MATCH m = MATCHexact;
+                            if (e->type->nextOf()->mod != tn->mod)
+                            {
+                                if (!tn->isConst())
+                                    return;
+                                m = MATCHconst;
+                            }
+                            if (!e->committed)
+                            {
+                                switch (tn->ty)
+                                {
+                                    case Tchar:
+                                        if (e->postfix == 'w' || e->postfix == 'd')
+                                            m = MATCHconvert;
+                                        result = m;
+                                        return;
+                                    case Twchar:
+                                        if (e->postfix != 'w')
+                                            m = MATCHconvert;
+                                        result = m;
+                                        return;
+                                    case Tdchar:
+                                        if (e->postfix != 'd')
+                                            m = MATCHconvert;
+                                        result = m;
+                                        return;
+                                }
+                            }
+                            break;
+                    }
+                }
+            }
+
+            visit((Expression *)e);
+        }
+
+        void visit(ArrayLiteralExp *e)
+        {
+        #if 0
+            printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            Type *typeb = e->type->toBasetype();
+            Type *tb = t->toBasetype();
+            if ((tb->ty == Tarray || tb->ty == Tsarray) &&
+                (typeb->ty == Tarray || typeb->ty == Tsarray))
+            {
+                result = MATCHexact;
+                Type *typen = typeb->nextOf()->toBasetype();
+
+                if (tb->ty == Tsarray)
+                {
+                    TypeSArray *tsa = (TypeSArray *)tb;
+                    if (e->elements->dim != tsa->dim->toInteger())
+                        result = MATCHnomatch;
+                }
+
+                Type *telement = tb->nextOf();
+                if (!e->elements->dim)
+                {
+                    if (typen->ty != Tvoid)
+                        result = typen->implicitConvTo(telement);
+                }
+                else
+                {
+                    if (e->basis)
+                    {
+                        MATCH m = e->basis->implicitConvTo(telement);
+                        if (m < result)
+                            result = m;
+                    }
+                    for (size_t i = 0; i < e->elements->dim; i++)
+                    {
+                        Expression *el = (*e->elements)[i];
+                        if (result == MATCHnomatch)
+                            break;
+                        if (!el)
+                            continue;
+                        MATCH m = el->implicitConvTo(telement);
+                        if (m < result)
+                            result = m;                     // remember worst match
+                    }
+                }
+
+                if (!result)
+                    result = e->type->implicitConvTo(t);
+
+                return;
+            }
+            else if (tb->ty == Tvector &&
+                (typeb->ty == Tarray || typeb->ty == Tsarray))
+            {
+                result = MATCHexact;
+                // Convert array literal to vector type
+                TypeVector *tv = (TypeVector *)tb;
+                TypeSArray *tbase = (TypeSArray *)tv->basetype;
+                assert(tbase->ty == Tsarray);
+                const size_t edim = e->elements->dim;
+                const size_t tbasedim = tbase->dim->toInteger();
+                if (edim > tbasedim)
+                {
+                    result = MATCHnomatch;
+                    return;
+                }
+
+                Type *telement = tv->elementType();
+                if (edim < tbasedim)
+                {
+                    Expression *el = typeb->nextOf()->defaultInitLiteral(e->loc);
+                    MATCH m = el->implicitConvTo(telement);
+                    if (m < result)
+                        result = m; // remember worst match
+                }
+                for (size_t i = 0; i < edim; i++)
+                {
+                    Expression *el = (*e->elements)[i];
+                    MATCH m = el->implicitConvTo(telement);
+                    if (m < result)
+                        result = m;                     // remember worst match
+                    if (result == MATCHnomatch)
+                        break;                          // no need to check for worse
+                }
+                return;
+            }
+
+            visit((Expression *)e);
+        }
+
+        void visit(AssocArrayLiteralExp *e)
+        {
+            Type *typeb = e->type->toBasetype();
+            Type *tb = t->toBasetype();
+            if (tb->ty == Taarray && typeb->ty == Taarray)
+            {
+                result = MATCHexact;
+                for (size_t i = 0; i < e->keys->dim; i++)
+                {
+                    Expression *el = (*e->keys)[i];
+                    MATCH m = el->implicitConvTo(((TypeAArray *)tb)->index);
+                    if (m < result)
+                        result = m;                     // remember worst match
+                    if (result == MATCHnomatch)
+                        break;                          // no need to check for worse
+                    el = (*e->values)[i];
+                    m = el->implicitConvTo(tb->nextOf());
+                    if (m < result)
+                        result = m;                     // remember worst match
+                    if (result == MATCHnomatch)
+                        break;                          // no need to check for worse
+                }
+                return;
+            }
+            else
+                visit((Expression *)e);
+        }
+
+        void visit(CallExp *e)
+        {
+#define LOG 0
+        #if LOG
+            printf("CallExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+
+            visit((Expression *)e);
+            if (result != MATCHnomatch)
+                return;
+
+            /* Allow the result of strongly pure functions to
+             * convert to immutable
+             */
+            if (e->f && e->f->isolateReturn())
+            {
+                result = e->type->immutableOf()->implicitConvTo(t);
+                if (result > MATCHconst)    // Match level is MATCHconst at best.
+                    result = MATCHconst;
+                return;
+            }
+
+            /* Conversion is 'const' conversion if:
+             * 1. function is pure (weakly pure is ok)
+             * 2. implicit conversion only fails because of mod bits
+             * 3. each function parameter can be implicitly converted to the mod bits
+             */
+            Type *tx = e->f ? e->f->type : e->e1->type;
+            tx = tx->toBasetype();
+            if (tx->ty != Tfunction)
+                return;
+            TypeFunction *tf = (TypeFunction *)tx;
+
+            if (tf->purity == PUREimpure)
+                return;
+            if (e->f && e->f->isNested())
+                return;
+
+            /* See if fail only because of mod bits.
+             *
+             * Bugzilla 14155: All pure functions can access global immutable data.
+             * So the returned pointer may refer an immutable global data,
+             * and then the returned pointer that points non-mutable object
+             * cannot be unique pointer.
+             *
+             * Example:
+             *  immutable g;
+             *  static this() { g = 1; }
+             *  const(int*) foo() pure { return &g; }
+             *  void test() {
+             *    immutable(int*) ip = foo(); // OK
+             *    int* mp = foo();            // should be disallowed
+             *  }
+             */
+            if (e->type->immutableOf()->implicitConvTo(t) < MATCHconst &&
+                e->type->addMod(MODshared)->implicitConvTo(t) < MATCHconst &&
+                e->type->implicitConvTo(t->addMod(MODshared)) < MATCHconst)
+            {
+                return;
+            }
+            // Allow a conversion to immutable type, or
+            // conversions of mutable types between thread-local and shared.
+
+            /* Get mod bits of what we're converting to
+             */
+            Type *tb = t->toBasetype();
+            MOD mod = tb->mod;
+            if (tf->isref)
+                ;
+            else
+            {
+                Type *ti = getIndirection(t);
+                if (ti)
+                    mod = ti->mod;
+            }
+#if LOG
+            printf("mod = x%x\n", mod);
+#endif
+            if (mod & MODwild)
+                return;                 // not sure what to do with this
+
+            /* Apply mod bits to each function parameter,
+             * and see if we can convert the function argument to the modded type
+             */
+
+            size_t nparams = Parameter::dim(tf->parameters);
+            size_t j = (tf->linkage == LINKd && tf->varargs == 1); // if TypeInfoArray was prepended
+            if (e->e1->op == TOKdotvar)
+            {
+                /* Treat 'this' as just another function argument
+                 */
+                DotVarExp *dve = (DotVarExp *)e->e1;
+                Type *targ = dve->e1->type;
+                if (targ->constConv(targ->castMod(mod)) == MATCHnomatch)
+                    return;
+            }
+            for (size_t i = j; i < e->arguments->dim; ++i)
+            {
+                Expression *earg = (*e->arguments)[i];
+                Type *targ = earg->type->toBasetype();
+#if LOG
+                printf("[%d] earg: %s, targ: %s\n", (int)i, earg->toChars(), targ->toChars());
+#endif
+                if (i - j < nparams)
+                {
+                    Parameter *fparam = Parameter::getNth(tf->parameters, i - j);
+                    if (fparam->storageClass & STClazy)
+                        return;                 // not sure what to do with this
+                    Type *tparam = fparam->type;
+                    if (!tparam)
+                        continue;
+                    if (fparam->storageClass & (STCout | STCref))
+                    {
+                        if (targ->constConv(tparam->castMod(mod)) == MATCHnomatch)
+                            return;
+                        continue;
+                    }
+                }
+
+#if LOG
+                printf("[%d] earg: %s, targm: %s\n", (int)i, earg->toChars(), targ->addMod(mod)->toChars());
+#endif
+                if (implicitMod(earg, targ, mod) == MATCHnomatch)
+                    return;
+            }
+
+            /* Success
+             */
+            result = MATCHconst;
+#undef LOG
+        }
+
+        void visit(AddrExp *e)
+        {
+        #if 0
+            printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            result = e->type->implicitConvTo(t);
+            //printf("\tresult = %d\n", result);
+
+            if (result != MATCHnomatch)
+                return;
+
+            // Look for pointers to functions where the functions are overloaded.
+
+            t = t->toBasetype();
+
+            if (e->e1->op == TOKoverloadset &&
+                (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
+            {
+                OverExp *eo = (OverExp *)e->e1;
+                FuncDeclaration *f = NULL;
+                for (size_t i = 0; i < eo->vars->a.dim; i++)
+                {
+                    Dsymbol *s = eo->vars->a[i];
+                    FuncDeclaration *f2 = s->isFuncDeclaration();
+                    assert(f2);
+                    if (f2->overloadExactMatch(t->nextOf()))
+                    {
+                        if (f)
+                        {
+                            /* Error if match in more than one overload set,
+                             * even if one is a 'better' match than the other.
+                             */
+                            ScopeDsymbol::multiplyDefined(e->loc, f, f2);
+                        }
+                        else
+                            f = f2;
+                        result = MATCHexact;
+                    }
+                }
+            }
+
+            if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tfunction &&
+                t->ty == Tpointer && t->nextOf()->ty == Tfunction &&
+                e->e1->op == TOKvar)
+            {
+                /* I don't think this can ever happen -
+                 * it should have been
+                 * converted to a SymOffExp.
+                 */
+                assert(0);
+            }
+
+            //printf("\tresult = %d\n", result);
+        }
+
+        void visit(SymOffExp *e)
+        {
+        #if 0
+            printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            result = e->type->implicitConvTo(t);
+            //printf("\tresult = %d\n", result);
+            if (result != MATCHnomatch)
+                return;
+
+            // Look for pointers to functions where the functions are overloaded.
+            t = t->toBasetype();
+            if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tfunction &&
+                (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
+            {
+                if (FuncDeclaration *f = e->var->isFuncDeclaration())
+                {
+                    f = f->overloadExactMatch(t->nextOf());
+                    if (f)
+                    {
+                        if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) ||
+                            (t->ty == Tpointer && !(f->needThis() || f->isNested())))
+                        {
+                            result = MATCHexact;
+                        }
+                    }
+                }
+            }
+            //printf("\tresult = %d\n", result);
+        }
+
+        void visit(DelegateExp *e)
+        {
+        #if 0
+            printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            result = e->type->implicitConvTo(t);
+            if (result != MATCHnomatch)
+                return;
+
+            // Look for pointers to functions where the functions are overloaded.
+            t = t->toBasetype();
+            if (e->type->ty == Tdelegate &&
+                t->ty == Tdelegate)
+            {
+                if (e->func && e->func->overloadExactMatch(t->nextOf()))
+                    result = MATCHexact;
+            }
+        }
+
+        void visit(FuncExp *e)
+        {
+            //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e->type, e->type ? e->type->toChars() : NULL, t->toChars());
+            MATCH m = e->matchType(t, NULL, NULL, 1);
+            if (m > MATCHnomatch)
+            {
+                result = m;
+                return;
+            }
+            visit((Expression *)e);
+        }
+
+        void visit(OrExp *e)
+        {
+            visit((Expression *)e);
+            if (result != MATCHnomatch)
+                return;
+
+            MATCH m1 = e->e1->implicitConvTo(t);
+            MATCH m2 = e->e2->implicitConvTo(t);
+
+            // Pick the worst match
+            result = (m1 < m2) ? m1 : m2;
+        }
+
+        void visit(XorExp *e)
+        {
+            visit((Expression *)e);
+            if (result != MATCHnomatch)
+                return;
+
+            MATCH m1 = e->e1->implicitConvTo(t);
+            MATCH m2 = e->e2->implicitConvTo(t);
+
+            // Pick the worst match
+            result = (m1 < m2) ? m1 : m2;
+        }
+
+        void visit(CondExp *e)
+        {
+            MATCH m1 = e->e1->implicitConvTo(t);
+            MATCH m2 = e->e2->implicitConvTo(t);
+            //printf("CondExp: m1 %d m2 %d\n", m1, m2);
+
+            // Pick the worst match
+            result = (m1 < m2) ? m1 : m2;
+        }
+
+        void visit(CommaExp *e)
+        {
+            e->e2->accept(this);
+        }
+
+        void visit(CastExp *e)
+        {
+        #if 0
+            printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            result = e->type->implicitConvTo(t);
+            if (result != MATCHnomatch)
+                return;
+
+            if (t->isintegral() &&
+                e->e1->type->isintegral() &&
+                e->e1->implicitConvTo(t) != MATCHnomatch)
+                result = MATCHconvert;
+            else
+                visit((Expression *)e);
+        }
+
+        void visit(NewExp *e)
+        {
+        #if 0
+            printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            visit((Expression *)e);
+            if (result != MATCHnomatch)
+                return;
+
+            /* Calling new() is like calling a pure function. We can implicitly convert the
+             * return from new() to t using the same algorithm as in CallExp, with the function
+             * 'arguments' being:
+             *    thisexp
+             *    newargs
+             *    arguments
+             *    .init
+             * 'member' and 'allocator' need to be pure.
+             */
+
+            /* See if fail only because of mod bits
+             */
+            if (e->type->immutableOf()->implicitConvTo(t->immutableOf()) == MATCHnomatch)
+                return;
+
+            /* Get mod bits of what we're converting to
+             */
+            Type *tb = t->toBasetype();
+            MOD mod = tb->mod;
+            if (Type *ti = getIndirection(t))
+                mod = ti->mod;
+#if LOG
+            printf("mod = x%x\n", mod);
+#endif
+            if (mod & MODwild)
+                return;                 // not sure what to do with this
+
+            /* Apply mod bits to each argument,
+             * and see if we can convert the argument to the modded type
+             */
+
+            if (e->thisexp)
+            {
+                /* Treat 'this' as just another function argument
+                 */
+                Type *targ = e->thisexp->type;
+                if (targ->constConv(targ->castMod(mod)) == MATCHnomatch)
+                    return;
+            }
+
+            /* Check call to 'allocator', then 'member'
+             */
+            FuncDeclaration *fd = e->allocator;
+            for (int count = 0; count < 2; ++count, (fd = e->member))
+            {
+                if (!fd)
+                    continue;
+                if (fd->errors || fd->type->ty != Tfunction)
+                    return;     // error
+                TypeFunction *tf = (TypeFunction *)fd->type;
+                if (tf->purity == PUREimpure)
+                    return;     // impure
+
+                if (fd == e->member)
+                {
+                    if (e->type->immutableOf()->implicitConvTo(t) < MATCHconst &&
+                        e->type->addMod(MODshared)->implicitConvTo(t) < MATCHconst &&
+                        e->type->implicitConvTo(t->addMod(MODshared)) < MATCHconst)
+                    {
+                        return;
+                    }
+                    // Allow a conversion to immutable type, or
+                    // conversions of mutable types between thread-local and shared.
+                }
+
+                Expressions *args = (fd == e->allocator) ? e->newargs : e->arguments;
+
+                size_t nparams = Parameter::dim(tf->parameters);
+                size_t j = (tf->linkage == LINKd && tf->varargs == 1); // if TypeInfoArray was prepended
+                for (size_t i = j; i < e->arguments->dim; ++i)
+                {
+                    Expression *earg = (*args)[i];
+                    Type *targ = earg->type->toBasetype();
+#if LOG
+                    printf("[%d] earg: %s, targ: %s\n", (int)i, earg->toChars(), targ->toChars());
+#endif
+                    if (i - j < nparams)
+                    {
+                        Parameter *fparam = Parameter::getNth(tf->parameters, i - j);
+                        if (fparam->storageClass & STClazy)
+                            return;                 // not sure what to do with this
+                        Type *tparam = fparam->type;
+                        if (!tparam)
+                            continue;
+                        if (fparam->storageClass & (STCout | STCref))
+                        {
+                            if (targ->constConv(tparam->castMod(mod)) == MATCHnomatch)
+                                return;
+                            continue;
+                        }
+                    }
+
+#if LOG
+                    printf("[%d] earg: %s, targm: %s\n", (int)i, earg->toChars(), targ->addMod(mod)->toChars());
+#endif
+                    if (implicitMod(earg, targ, mod) == MATCHnomatch)
+                        return;
+                }
+            }
+
+            /* If no 'member', then construction is by simple assignment,
+             * and just straight check 'arguments'
+             */
+            if (!e->member && e->arguments)
+            {
+                for (size_t i = 0; i < e->arguments->dim; ++i)
+                {
+                    Expression *earg = (*e->arguments)[i];
+                    if (!earg)  // Bugzilla 14853: if it's on overlapped field
+                        continue;
+                    Type *targ = earg->type->toBasetype();
+#if LOG
+                    printf("[%d] earg: %s, targ: %s\n", (int)i, earg->toChars(), targ->toChars());
+                    printf("[%d] earg: %s, targm: %s\n", (int)i, earg->toChars(), targ->addMod(mod)->toChars());
+#endif
+                    if (implicitMod(earg, targ, mod) == MATCHnomatch)
+                        return;
+                }
+            }
+
+            /* Consider the .init expression as an argument
+             */
+            Type *ntb = e->newtype->toBasetype();
+            if (ntb->ty == Tarray)
+                ntb = ntb->nextOf()->toBasetype();
+            if (ntb->ty == Tstruct)
+            {
+                // Don't allow nested structs - uplevel reference may not be convertible
+                StructDeclaration *sd = ((TypeStruct *)ntb)->sym;
+                sd->size(e->loc);              // resolve any forward references
+                if (sd->isNested())
+                    return;
+            }
+            if (ntb->isZeroInit(e->loc))
+            {
+                /* Zeros are implicitly convertible, except for special cases.
+                 */
+                if (ntb->ty == Tclass)
+                {
+                    /* With new() must look at the class instance initializer.
+                     */
+                    ClassDeclaration *cd = ((TypeClass *)ntb)->sym;
+
+                    cd->size(e->loc);          // resolve any forward references
+
+                    if (cd->isNested())
+                        return;                 // uplevel reference may not be convertible
+
+                    assert(!cd->isInterfaceDeclaration());
+
+                    struct ClassCheck
+                    {
+                        static bool convertible(Loc loc, ClassDeclaration *cd, MOD mod)
+                        {
+                            for (size_t i = 0; i < cd->fields.dim; i++)
+                            {
+                                VarDeclaration *v = cd->fields[i];
+                                Initializer *init = v->_init;
+                                if (init)
+                                {
+                                    if (init->isVoidInitializer())
+                                        ;
+                                    else if (ExpInitializer *ei = init->isExpInitializer())
+                                    {
+                                        Type *tb = v->type->toBasetype();
+                                        if (implicitMod(ei->exp, tb, mod) == MATCHnomatch)
+                                            return false;
+                                    }
+                                    else
+                                    {
+                                        /* Enhancement: handle StructInitializer and ArrayInitializer
+                                         */
+                                        return false;
+                                    }
+                                }
+                                else if (!v->type->isZeroInit(loc))
+                                    return false;
+                            }
+                            return cd->baseClass ? convertible(loc, cd->baseClass, mod) : true;
+                        }
+                    };
+
+                    if (!ClassCheck::convertible(e->loc, cd, mod))
+                        return;
+                }
+            }
+            else
+            {
+                Expression *earg = e->newtype->defaultInitLiteral(e->loc);
+                Type *targ = e->newtype->toBasetype();
+
+                if (implicitMod(earg, targ, mod) == MATCHnomatch)
+                    return;
+            }
+
+            /* Success
+             */
+            result = MATCHconst;
+        }
+
+        void visit(SliceExp *e)
+        {
+            //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e->toChars(), e->type->toChars());
+            visit((Expression *)e);
+            if (result != MATCHnomatch)
+                return;
+
+            Type *tb = t->toBasetype();
+            Type *typeb = e->type->toBasetype();
+            if (tb->ty == Tsarray && typeb->ty == Tarray)
+            {
+                typeb = toStaticArrayType(e);
+                if (typeb)
+                    result = typeb->implicitConvTo(t);
+                return;
+            }
+
+            /* If the only reason it won't convert is because of the mod bits,
+             * then test for conversion by seeing if e1 can be converted with those
+             * same mod bits.
+             */
+            Type *t1b = e->e1->type->toBasetype();
+            if (tb->ty == Tarray && typeb->equivalent(tb))
+            {
+                Type *tbn = tb->nextOf();
+                Type *tx = NULL;
+
+                /* If e->e1 is dynamic array or pointer, the uniqueness of e->e1
+                 * is equivalent with the uniqueness of the referred data. And in here
+                 * we can have arbitrary typed reference for that.
+                 */
+                if (t1b->ty == Tarray)
+                    tx = tbn->arrayOf();
+                if (t1b->ty == Tpointer)
+                    tx = tbn->pointerTo();
+
+                /* If e->e1 is static array, at least it should be an rvalue.
+                 * If not, e->e1 is a reference, and its uniqueness does not link
+                 * to the uniqueness of the referred data.
+                 */
+                if (t1b->ty == Tsarray && !e->e1->isLvalue())
+                    tx = tbn->sarrayOf(t1b->size() / tbn->size());
+
+                if (tx)
+                {
+                    result = e->e1->implicitConvTo(tx);
+                    if (result > MATCHconst)    // Match level is MATCHconst at best.
+                        result = MATCHconst;
+                }
+            }
+
+            // Enhancement 10724
+            if (tb->ty == Tpointer && e->e1->op == TOKstring)
+                e->e1->accept(this);
+        }
+    };
+
+    ImplicitConvTo v(t);
+    e->accept(&v);
+    return v.result;
+}
+
+Type *toStaticArrayType(SliceExp *e)
+{
+    if (e->lwr && e->upr)
+    {
+        // For the following code to work, e should be optimized beforehand.
+        // (eg. $ in lwr and upr should be already resolved, if possible)
+        Expression *lwr = e->lwr->optimize(WANTvalue);
+        Expression *upr = e->upr->optimize(WANTvalue);
+        if (lwr->isConst() && upr->isConst())
+        {
+            size_t len = (size_t)(upr->toUInteger() - lwr->toUInteger());
+            return e->type->toBasetype()->nextOf()->sarrayOf(len);
+        }
+    }
+    else
+    {
+        Type *t1b = e->e1->type->toBasetype();
+        if (t1b->ty == Tsarray)
+            return t1b;
+    }
+    return NULL;
+}
+
+/* ==================== castTo ====================== */
+
+/**************************************
+ * Do an explicit cast.
+ * Assume that the 'this' expression does not have any indirections.
+ */
+
+Expression *castTo(Expression *e, Scope *sc, Type *t)
+{
+    class CastTo : public Visitor
+    {
+    public:
+        Type *t;
+        Scope *sc;
+        Expression *result;
+
+        CastTo(Scope *sc, Type *t)
+            : sc(sc), t(t)
+        {
+            result = NULL;
+        }
+
+        void visit(Expression *e)
+        {
+            //printf("Expression::castTo(this=%s, t=%s)\n", e->toChars(), t->toChars());
+        #if 0
+            printf("Expression::castTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            if (e->type->equals(t))
+            {
+                result = e;
+                return;
+            }
+            if (e->op == TOKvar)
+            {
+                VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
+                if (v && v->storage_class & STCmanifest)
+                {
+                    result = e->ctfeInterpret();
+                    result = result->castTo(sc, t);
+                    return;
+                }
+            }
+
+            Type *tob = t->toBasetype();
+            Type *t1b = e->type->toBasetype();
+            if (tob->equals(t1b))
+            {
+                result = e->copy();  // because of COW for assignment to e->type
+                result->type = t;
+                return;
+            }
+
+            /* Make semantic error against invalid cast between concrete types.
+             * Assume that 'e' is never be any placeholder expressions.
+             * The result of these checks should be consistent with CastExp::toElem().
+             */
+
+            // Fat Value types
+            const bool tob_isFV = (tob->ty == Tstruct || tob->ty == Tsarray || tob->ty == Tvector);
+            const bool t1b_isFV = (t1b->ty == Tstruct || t1b->ty == Tsarray || t1b->ty == Tvector);
+
+            // Fat Reference types
+            const bool tob_isFR = (tob->ty == Tarray || tob->ty == Tdelegate);
+            const bool t1b_isFR = (t1b->ty == Tarray || t1b->ty == Tdelegate);
+
+            // Reference types
+            const bool tob_isR = (tob_isFR || tob->ty == Tpointer || tob->ty == Taarray || tob->ty == Tclass);
+            const bool t1b_isR = (t1b_isFR || t1b->ty == Tpointer || t1b->ty == Taarray || t1b->ty == Tclass);
+
+            // Arithmetic types (== valueable basic types)
+            const bool tob_isA = ((tob->isintegral() || tob->isfloating()) && tob->ty != Tvector);
+            const bool t1b_isA = ((t1b->isintegral() || t1b->isfloating()) && t1b->ty != Tvector);
+
+            if (AggregateDeclaration *t1ad = isAggregate(t1b))
+            {
+                AggregateDeclaration *toad = isAggregate(tob);
+                if (t1ad != toad && t1ad->aliasthis)
+                {
+                    if (t1b->ty == Tclass && tob->ty == Tclass)
+                    {
+                        ClassDeclaration *t1cd = t1b->isClassHandle();
+                        ClassDeclaration *tocd = tob->isClassHandle();
+                        int offset;
+                        if (tocd->isBaseOf(t1cd, &offset))
+                             goto Lok;
+                    }
+
+                    /* Forward the cast to our alias this member, rewrite to:
+                     *   cast(to)e1.aliasthis
+                     */
+                    result = resolveAliasThis(sc, e);
+                    result = result->castTo(sc, t);
+                    return;
+                }
+            }
+            else if (tob->ty == Tvector && t1b->ty != Tvector)
+            {
+                //printf("test1 e = %s, e->type = %s, tob = %s\n", e->toChars(), e->type->toChars(), tob->toChars());
+                TypeVector *tv = (TypeVector *)tob;
+                result = new CastExp(e->loc, e, tv->elementType());
+                result = new VectorExp(e->loc, result, tob);
+                result = ::semantic(result, sc);
+                return;
+            }
+            else if (tob->ty != Tvector && t1b->ty == Tvector)
+            {
+                // T[n] <-- __vector(U[m])
+                if (tob->ty == Tsarray)
+                {
+                    if (t1b->size(e->loc) == tob->size(e->loc))
+                        goto Lok;
+                }
+                goto Lfail;
+            }
+            else if (t1b->implicitConvTo(tob) == MATCHconst && t->equals(e->type->constOf()))
+            {
+                result = e->copy();
+                result->type = t;
+                return;
+            }
+
+            // arithmetic values vs. other arithmetic values
+            // arithmetic values vs. T*
+            if (tob_isA && (t1b_isA || t1b->ty == Tpointer) ||
+                t1b_isA && (tob_isA || tob->ty == Tpointer))
+            {
+                goto Lok;
+            }
+
+            // arithmetic values vs. references or fat values
+            if (tob_isA && (t1b_isR || t1b_isFV) ||
+                t1b_isA && (tob_isR || tob_isFV))
+            {
+                goto Lfail;
+            }
+
+            // Bugzlla 3133: A cast between fat values is possible only when the sizes match.
+            if (tob_isFV && t1b_isFV)
+            {
+                if (t1b->size(e->loc) == tob->size(e->loc))
+                    goto Lok;
+                e->error("cannot cast expression %s of type %s to %s because of different sizes",
+                    e->toChars(), e->type->toChars(), t->toChars());
+                result = new ErrorExp();
+                return;
+            }
+
+            // Fat values vs. null or references
+            if (tob_isFV && (t1b->ty == Tnull || t1b_isR) ||
+                t1b_isFV && (tob->ty == Tnull || tob_isR))
+            {
+                if (tob->ty == Tpointer && t1b->ty == Tsarray)
+                {
+                    // T[n] sa;
+                    // cast(U*)sa; // ==> cast(U*)sa.ptr;
+                    result = new AddrExp(e->loc, e);
+                    result->type = t;
+                    return;
+                }
+                if (tob->ty == Tarray && t1b->ty == Tsarray)
+                {
+                    // T[n] sa;
+                    // cast(U[])sa; // ==> cast(U[])sa[];
+                    d_uns64 fsize = t1b->nextOf()->size();
+                    d_uns64 tsize = tob->nextOf()->size();
+                    if ((((TypeSArray *)t1b)->dim->toInteger() * fsize) % tsize != 0)
+                    {
+                        // copied from sarray_toDarray() in e2ir.c
+                        e->error("cannot cast expression %s of type %s to %s since sizes don't line up",
+                            e->toChars(), e->type->toChars(), t->toChars());
+                        result = new ErrorExp();
+                        return;
+                    }
+                    goto Lok;
+                }
+                goto Lfail;
+            }
+
+            /* For references, any reinterpret casts are allowed to same 'ty' type.
+             *      T* to U*
+             *      R1 function(P1) to R2 function(P2)
+             *      R1 delegate(P1) to R2 delegate(P2)
+             *      T[] to U[]
+             *      V1[K1] to V2[K2]
+             *      class/interface A to B  (will be a dynamic cast if possible)
+             */
+            if (tob->ty == t1b->ty && tob_isR && t1b_isR)
+                goto Lok;
+
+            // typeof(null) <-- non-null references or values
+            if (tob->ty == Tnull && t1b->ty != Tnull)
+                goto Lfail;     // Bugzilla 14629
+            // typeof(null) --> non-null references or arithmetic values
+            if (t1b->ty == Tnull && tob->ty != Tnull)
+                goto Lok;
+
+            // Check size mismatch of references.
+            // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof.
+            if (tob_isFR && t1b_isR ||
+                t1b_isFR && tob_isR)
+            {
+                if (tob->ty == Tpointer && t1b->ty == Tarray)
+                {
+                    // T[] da;
+                    // cast(U*)da; // ==> cast(U*)da.ptr;
+                    goto Lok;
+                }
+                if (tob->ty == Tpointer && t1b->ty == Tdelegate)
+                {
+                    // void delegate() dg;
+                    // cast(U*)dg; // ==> cast(U*)dg.ptr;
+                    // Note that it happens even when U is a Tfunction!
+                    e->deprecation("casting from %s to %s is deprecated", e->type->toChars(), t->toChars());
+                    goto Lok;
+                }
+                goto Lfail;
+            }
+
+            if (t1b->ty == Tvoid && tob->ty != Tvoid)
+            {
+            Lfail:
+                e->error("cannot cast expression %s of type %s to %s",
+                    e->toChars(), e->type->toChars(), t->toChars());
+                result = new ErrorExp();
+                return;
+            }
+
+        Lok:
+            result = new CastExp(e->loc, e, t);
+            result->type = t;       // Don't call semantic()
+            //printf("Returning: %s\n", result->toChars());
+        }
+
+        void visit(ErrorExp *e)
+        {
+            result = e;
+        }
+
+        void visit(RealExp *e)
+        {
+            if (!e->type->equals(t))
+            {
+                if ((e->type->isreal() && t->isreal()) ||
+                    (e->type->isimaginary() && t->isimaginary())
+                   )
+                {
+                    result = e->copy();
+                    result->type = t;
+                }
+                else
+                    visit((Expression *)e);
+                return;
+            }
+            result = e;
+        }
+
+        void visit(ComplexExp *e)
+        {
+            if (!e->type->equals(t))
+            {
+                if (e->type->iscomplex() && t->iscomplex())
+                {
+                    result = e->copy();
+                    result->type = t;
+                }
+                else
+                    visit((Expression *)e);
+                return;
+            }
+            result = e;
+        }
+
+        void visit(NullExp *e)
+        {
+            //printf("NullExp::castTo(t = %s) %s\n", t->toChars(), toChars());
+            visit((Expression *)e);
+            if (result->op == TOKnull)
+            {
+                NullExp *ex = (NullExp *)result;
+                ex->committed = 1;
+                return;
+            }
+        }
+
+        void visit(StructLiteralExp *e)
+        {
+            visit((Expression *)e);
+            if (result->op == TOKstructliteral)
+                ((StructLiteralExp *)result)->stype = t; // commit type
+        }
+
+        void visit(StringExp *e)
+        {
+            /* This follows copy-on-write; any changes to 'this'
+             * will result in a copy.
+             * The this->string member is considered immutable.
+             */
+            int copied = 0;
+
+            //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), e->toChars(), e->committed);
+
+            if (!e->committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
+            {
+                e->error("cannot convert string literal to void*");
+                result = new ErrorExp();
+                return;
+            }
+
+            StringExp *se = e;
+            if (!e->committed)
+            {
+                se = (StringExp *)e->copy();
+                se->committed = 1;
+                copied = 1;
+            }
+
+            if (e->type->equals(t))
+            {
+                result = se;
+                return;
+            }
+
+            Type *tb = t->toBasetype();
+            //printf("\ttype = %s\n", e->type->toChars());
+            if (tb->ty == Tdelegate && e->type->toBasetype()->ty != Tdelegate)
+            {
+                visit((Expression *)e);
+                return;
+            }
+
+            Type *typeb = e->type->toBasetype();
+            if (typeb->equals(tb))
+            {
+                if (!copied)
+                {
+                    se = (StringExp *)e->copy();
+                    copied = 1;
+                }
+                se->type = t;
+                result = se;
+                return;
+            }
+
+            /* Handle reinterpret casts:
+             *  cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000]
+             *  cast(wchar[2])"abcd"c --> [\u6261, \u6463]
+             *  cast(wchar[1])"abcd"c --> [\u6261]
+             */
+            if (e->committed && tb->ty == Tsarray && typeb->ty == Tarray)
+            {
+                se = (StringExp *)e->copy();
+                d_uns64 szx = tb->nextOf()->size();
+                assert(szx <= 255);
+                se->sz = (unsigned char)szx;
+                se->len = (size_t)((TypeSArray *)tb)->dim->toInteger();
+                se->committed = 1;
+                se->type = t;
+
+                /* Assure space for terminating 0
+                 */
+                if ((se->len + 1) * se->sz > (e->len + 1) * e->sz)
+                {
+                    void *s = (void *)mem.xmalloc((se->len + 1) * se->sz);
+                    memcpy(s, se->string, se->len * se->sz);
+                    memset((char *)s + se->len * se->sz, 0, se->sz);
+                    se->string = s;
+                }
+                result = se;
+                return;
+            }
+
+            if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer)
+            {
+                if (!copied)
+                {
+                    se = (StringExp *)e->copy();
+                    copied = 1;
+                }
+                goto Lcast;
+            }
+            if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer)
+            {
+                if (!copied)
+                {
+                    se = (StringExp *)e->copy();
+                    copied = 1;
+                }
+                goto Lcast;
+            }
+
+            if (typeb->nextOf()->size() == tb->nextOf()->size())
+            {
+                if (!copied)
+                {
+                    se = (StringExp *)e->copy();
+                    copied = 1;
+                }
+                if (tb->ty == Tsarray)
+                    goto L2;    // handle possible change in static array dimension
+                se->type = t;
+                result = se;
+                return;
+            }
+
+            if (e->committed)
+                goto Lcast;
+
+        #define X(tf,tt)        ((int)(tf) * 256 + (int)(tt))
+            {
+            OutBuffer buffer;
+            size_t newlen = 0;
+            int tfty = typeb->nextOf()->toBasetype()->ty;
+            int ttty = tb->nextOf()->toBasetype()->ty;
+            switch (X(tfty, ttty))
+            {
+                case X(Tchar, Tchar):
+                case X(Twchar,Twchar):
+                case X(Tdchar,Tdchar):
+                    break;
+
+                case X(Tchar, Twchar):
+                    for (size_t u = 0; u < e->len;)
+                    {
+                        unsigned c;
+                        const char *p = utf_decodeChar((utf8_t *)se->string, e->len, &u, &c);
+                        if (p)
+                            e->error("%s", p);
+                        else
+                            buffer.writeUTF16(c);
+                    }
+                    newlen = buffer.offset / 2;
+                    buffer.writeUTF16(0);
+                    goto L1;
+
+                case X(Tchar, Tdchar):
+                    for (size_t u = 0; u < e->len;)
+                    {
+                        unsigned c;
+                        const char *p = utf_decodeChar((utf8_t *)se->string, e->len, &u, &c);
+                        if (p)
+                            e->error("%s", p);
+                        buffer.write4(c);
+                        newlen++;
+                    }
+                    buffer.write4(0);
+                    goto L1;
+
+                case X(Twchar,Tchar):
+                    for (size_t u = 0; u < e->len;)
+                    {
+                        unsigned c;
+                        const char *p = utf_decodeWchar((unsigned short *)se->string, e->len, &u, &c);
+                        if (p)
+                            e->error("%s", p);
+                        else
+                            buffer.writeUTF8(c);
+                    }
+                    newlen = buffer.offset;
+                    buffer.writeUTF8(0);
+                    goto L1;
+
+                case X(Twchar,Tdchar):
+                    for (size_t u = 0; u < e->len;)
+                    {
+                        unsigned c;
+                        const char *p = utf_decodeWchar((unsigned short *)se->string, e->len, &u, &c);
+                        if (p)
+                            e->error("%s", p);
+                        buffer.write4(c);
+                        newlen++;
+                    }
+                    buffer.write4(0);
+                    goto L1;
+
+                case X(Tdchar,Tchar):
+                    for (size_t u = 0; u < e->len; u++)
+                    {
+                        unsigned c = ((unsigned *)se->string)[u];
+                        if (!utf_isValidDchar(c))
+                            e->error("invalid UCS-32 char \\U%08x", c);
+                        else
+                            buffer.writeUTF8(c);
+                        newlen++;
+                    }
+                    newlen = buffer.offset;
+                    buffer.writeUTF8(0);
+                    goto L1;
+
+                case X(Tdchar,Twchar):
+                    for (size_t u = 0; u < e->len; u++)
+                    {
+                        unsigned c = ((unsigned *)se->string)[u];
+                        if (!utf_isValidDchar(c))
+                            e->error("invalid UCS-32 char \\U%08x", c);
+                        else
+                            buffer.writeUTF16(c);
+                        newlen++;
+                    }
+                    newlen = buffer.offset / 2;
+                    buffer.writeUTF16(0);
+                    goto L1;
+
+                L1:
+                    if (!copied)
+                    {
+                        se = (StringExp *)e->copy();
+                        copied = 1;
+                    }
+                    se->string = buffer.extractData();
+                    se->len = newlen;
+
+                    {
+                        d_uns64 szx = tb->nextOf()->size();
+                        assert(szx <= 255);
+                        se->sz = (unsigned char)szx;
+                    }
+                    break;
+
+                default:
+                    assert(typeb->nextOf()->size() != tb->nextOf()->size());
+                    goto Lcast;
+            }
+            }
+        #undef X
+        L2:
+            assert(copied);
+
+            // See if need to truncate or extend the literal
+            if (tb->ty == Tsarray)
+            {
+                size_t dim2 = (size_t)((TypeSArray *)tb)->dim->toInteger();
+
+                //printf("dim from = %d, to = %d\n", (int)se->len, (int)dim2);
+
+                // Changing dimensions
+                if (dim2 != se->len)
+                {
+                    // Copy when changing the string literal
+                    size_t newsz = se->sz;
+                    size_t d = (dim2 < se->len) ? dim2 : se->len;
+                    void *s = (void *)mem.xmalloc((dim2 + 1) * newsz);
+                    memcpy(s, se->string, d * newsz);
+                    // Extend with 0, add terminating 0
+                    memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz);
+                    se->string = s;
+                    se->len = dim2;
+                }
+            }
+            se->type = t;
+            result = se;
+            return;
+
+        Lcast:
+            result = new CastExp(e->loc, se, t);
+            result->type = t;        // so semantic() won't be run on e
+        }
+
+        void visit(AddrExp *e)
+        {
+            Type *tb;
+
+        #if 0
+            printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            result = e;
+
+            tb = t->toBasetype();
+            e->type = e->type->toBasetype();
+            if (!tb->equals(e->type))
+            {
+                // Look for pointers to functions where the functions are overloaded.
+
+                if (e->e1->op == TOKoverloadset &&
+                    (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
+                {
+                    OverExp *eo = (OverExp *)e->e1;
+                    FuncDeclaration *f = NULL;
+                    for (size_t i = 0; i < eo->vars->a.dim; i++)
+                    {
+                        Dsymbol *s = eo->vars->a[i];
+                        FuncDeclaration *f2 = s->isFuncDeclaration();
+                        assert(f2);
+                        if (f2->overloadExactMatch(t->nextOf()))
+                        {
+                            if (f)
+                            {
+                                /* Error if match in more than one overload set,
+                                 * even if one is a 'better' match than the other.
+                                 */
+                                ScopeDsymbol::multiplyDefined(e->loc, f, f2);
+                            }
+                            else
+                                f = f2;
+                        }
+                    }
+                    if (f)
+                    {
+                        f->tookAddressOf++;
+                        SymOffExp *se = new SymOffExp(e->loc, f, 0, false);
+                        ::semantic(se, sc);
+                        // Let SymOffExp::castTo() do the heavy lifting
+                        visit(se);
+                        return;
+                    }
+                }
+
+                if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tfunction &&
+                    tb->ty == Tpointer && tb->nextOf()->ty == Tfunction &&
+                    e->e1->op == TOKvar)
+                {
+                    VarExp *ve = (VarExp *)e->e1;
+                    FuncDeclaration *f = ve->var->isFuncDeclaration();
+                    if (f)
+                    {
+                        assert(f->isImportedSymbol());
+                        f = f->overloadExactMatch(tb->nextOf());
+                        if (f)
+                        {
+                            result = new VarExp(e->loc, f, false);
+                            result->type = f->type;
+                            result = new AddrExp(e->loc, result);
+                            result->type = t;
+                            return;
+                        }
+                    }
+                }
+
+                if (FuncDeclaration *f = isFuncAddress(e))
+                {
+                    if (f->checkForwardRef(e->loc))
+                    {
+                        result = new ErrorExp();
+                        return;
+                    }
+                }
+
+                visit((Expression *)e);
+            }
+            result->type = t;
+        }
+
+        void visit(TupleExp *e)
+        {
+            if (e->type->equals(t))
+            {
+                result = e;
+                return;
+            }
+
+            TupleExp *te = (TupleExp *)e->copy();
+            te->e0 = e->e0 ? e->e0->copy() : NULL;
+            te->exps = (Expressions *)e->exps->copy();
+            for (size_t i = 0; i < te->exps->dim; i++)
+            {
+                Expression *ex = (*te->exps)[i];
+                ex = ex->castTo(sc, t);
+                (*te->exps)[i] = ex;
+            }
+            result = te;
+
+            /* Questionable behavior: In here, result->type is not set to t.
+             * Therefoe:
+             *  TypeTuple!(int, int) values;
+             *  auto values2 = cast(long)values;
+             *  // typeof(values2) == TypeTuple!(int, int) !!
+             *
+             * Only when the casted tuple is immediately expanded, it would work.
+             *  auto arr = [cast(long)values];
+             *  // typeof(arr) == long[]
+             */
+        }
+
+        void visit(ArrayLiteralExp *e)
+        {
+        #if 0
+            printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            if (e->type == t)
+            {
+                result = e;
+                return;
+            }
+            ArrayLiteralExp *ae = e;
+            Type *typeb = e->type->toBasetype();
+            Type *tb = t->toBasetype();
+            if ((tb->ty == Tarray || tb->ty == Tsarray) &&
+                (typeb->ty == Tarray || typeb->ty == Tsarray))
+            {
+                if (tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)
+                {
+                    // Don't do anything to cast non-void[] to void[]
+                }
+                else if (typeb->ty == Tsarray && typeb->nextOf()->toBasetype()->ty == Tvoid)
+                {
+                    // Don't do anything for casting void[n] to others
+                }
+                else
+                {
+                    if (tb->ty == Tsarray)
+                    {
+                        TypeSArray *tsa = (TypeSArray *)tb;
+                        if (e->elements->dim != tsa->dim->toInteger())
+                            goto L1;
+                    }
+
+                    ae = (ArrayLiteralExp *)e->copy();
+                    if (e->basis)
+                        ae->basis = e->basis->castTo(sc, tb->nextOf());
+                    ae->elements = e->elements->copy();
+                    for (size_t i = 0; i < e->elements->dim; i++)
+                    {
+                        Expression *ex = (*e->elements)[i];
+                        if (!ex)
+                            continue;
+                        ex = ex->castTo(sc, tb->nextOf());
+                        (*ae->elements)[i] = ex;
+                    }
+                    ae->type = t;
+                    result = ae;
+                    return;
+                }
+            }
+            else if (tb->ty == Tpointer && typeb->ty == Tsarray)
+            {
+                Type *tp = typeb->nextOf()->pointerTo();
+                if (!tp->equals(ae->type))
+                {
+                    ae = (ArrayLiteralExp *)e->copy();
+                    ae->type = tp;
+                }
+            }
+            else if (tb->ty == Tvector &&
+                (typeb->ty == Tarray || typeb->ty == Tsarray))
+            {
+                // Convert array literal to vector type
+                TypeVector *tv = (TypeVector *)tb;
+                TypeSArray *tbase = (TypeSArray *)tv->basetype;
+                assert(tbase->ty == Tsarray);
+                const size_t edim = e->elements->dim;
+                const size_t tbasedim = tbase->dim->toInteger();
+                if (edim > tbasedim)
+                    goto L1;
+
+                ae = (ArrayLiteralExp *)e->copy();
+                ae->type = tbase;   // Bugzilla 12642
+                ae->elements = e->elements->copy();
+                Type *telement = tv->elementType();
+                for (size_t i = 0; i < edim; i++)
+                {
+                    Expression *ex = (*e->elements)[i];
+                    ex = ex->castTo(sc, telement);
+                    (*ae->elements)[i] = ex;
+                }
+                // Fill in the rest with the default initializer
+                ae->elements->setDim(tbasedim);
+                for (size_t i = edim; i < tbasedim; i++)
+                {
+                    Expression *ex = typeb->nextOf()->defaultInitLiteral(e->loc);
+                    ex = ex->castTo(sc, telement);
+                    (*ae->elements)[i] = ex;
+                }
+                Expression *ev = new VectorExp(e->loc, ae, tb);
+                ev = ::semantic(ev, sc);
+                result = ev;
+                return;
+            }
+        L1:
+            visit((Expression *)ae);
+        }
+
+        void visit(AssocArrayLiteralExp *e)
+        {
+            if (e->type == t)
+            {
+                result = e;
+                return;
+            }
+            Type *typeb = e->type->toBasetype();
+            Type *tb = t->toBasetype();
+            if (tb->ty == Taarray && typeb->ty == Taarray &&
+                tb->nextOf()->toBasetype()->ty != Tvoid)
+            {
+                AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e->copy();
+                ae->keys = e->keys->copy();
+                ae->values = e->values->copy();
+                assert(e->keys->dim == e->values->dim);
+                for (size_t i = 0; i < e->keys->dim; i++)
+                {
+                    Expression *ex = (*e->values)[i];
+                    ex = ex->castTo(sc, tb->nextOf());
+                    (*ae->values)[i] = ex;
+
+                    ex = (*e->keys)[i];
+                    ex = ex->castTo(sc, ((TypeAArray *)tb)->index);
+                    (*ae->keys)[i] = ex;
+                }
+                ae->type = t;
+                result = ae;
+                return;
+            }
+            visit((Expression *)e);
+        }
+
+        void visit(SymOffExp *e)
+        {
+        #if 0
+            printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            if (e->type == t && !e->hasOverloads)
+            {
+                result = e;
+                return;
+            }
+            Type *tb = t->toBasetype();
+            Type *typeb = e->type->toBasetype();
+
+            if (tb->equals(typeb))
+            {
+                result = e->copy();
+                result->type = t;
+                ((SymOffExp *)result)->hasOverloads = false;
+                return;
+            }
+
+            // Look for pointers to functions where the functions are overloaded.
+            if (e->hasOverloads &&
+                typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction &&
+                (tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction)
+            {
+                FuncDeclaration *f = e->var->isFuncDeclaration();
+                f = f ? f->overloadExactMatch(tb->nextOf()) : NULL;
+                if (f)
+                {
+                    if (tb->ty == Tdelegate)
+                    {
+                        if (f->needThis() && hasThis(sc))
+                        {
+                            result = new DelegateExp(e->loc, new ThisExp(e->loc), f, false);
+                            result = ::semantic(result, sc);
+                        }
+                        else if (f->isNested())
+                        {
+                            result = new DelegateExp(e->loc, new IntegerExp(0), f, false);
+                            result = ::semantic(result, sc);
+                        }
+                        else if (f->needThis())
+                        {
+                            e->error("no 'this' to create delegate for %s", f->toChars());
+                            result = new ErrorExp();
+                            return;
+                        }
+                        else
+                        {
+                            e->error("cannot cast from function pointer to delegate");
+                            result = new ErrorExp();
+                            return;
+                        }
+                    }
+                    else
+                    {
+                        result = new SymOffExp(e->loc, f, 0, false);
+                        result->type = t;
+                    }
+                    f->tookAddressOf++;
+                    return;
+                }
+            }
+
+            if (FuncDeclaration *f = isFuncAddress(e))
+            {
+                if (f->checkForwardRef(e->loc))
+                {
+                    result = new ErrorExp();
+                    return;
+                }
+            }
+
+            visit((Expression *)e);
+        }
+
+        void visit(DelegateExp *e)
+        {
+        #if 0
+            printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n",
+                e->toChars(), e->type->toChars(), t->toChars());
+        #endif
+            static const char msg[] = "cannot form delegate due to covariant return type";
+
+            Type *tb = t->toBasetype();
+            Type *typeb = e->type->toBasetype();
+            if (!tb->equals(typeb) || e->hasOverloads)
+            {
+                // Look for delegates to functions where the functions are overloaded.
+                if (typeb->ty == Tdelegate &&
+                    tb->ty == Tdelegate)
+                {
+                    if (e->func)
+                    {
+                        FuncDeclaration *f = e->func->overloadExactMatch(tb->nextOf());
+                        if (f)
+                        {
+                            int offset;
+                            if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset)
+                                e->error("%s", msg);
+                            f->tookAddressOf++;
+                            result = new DelegateExp(e->loc, e->e1, f, false);
+                            result->type = t;
+                            return;
+                        }
+                        if (e->func->tintro)
+                            e->error("%s", msg);
+                    }
+                }
+
+                if (FuncDeclaration *f = isFuncAddress(e))
+                {
+                    if (f->checkForwardRef(e->loc))
+                    {
+                        result = new ErrorExp();
+                        return;
+                    }
+                }
+
+                visit((Expression *)e);
+            }
+            else
+            {
+                int offset;
+                e->func->tookAddressOf++;
+                if (e->func->tintro && e->func->tintro->nextOf()->isBaseOf(e->func->type->nextOf(), &offset) && offset)
+                    e->error("%s", msg);
+                result = e->copy();
+                result->type = t;
+            }
+        }
+
+        void visit(FuncExp *e)
+        {
+            //printf("FuncExp::castTo type = %s, t = %s\n", e->type->toChars(), t->toChars());
+            FuncExp *fe;
+            if (e->matchType(t, sc, &fe, 1) > MATCHnomatch)
+            {
+                result = fe;
+                return;
+            }
+            visit((Expression *)e);
+        }
+
+        void visit(CondExp *e)
+        {
+            if (!e->type->equals(t))
+            {
+                result = new CondExp(e->loc, e->econd, e->e1->castTo(sc, t), e->e2->castTo(sc, t));
+                result->type = t;
+                return;
+            }
+            result = e;
+        }
+
+        void visit(CommaExp *e)
+        {
+            Expression *e2c = e->e2->castTo(sc, t);
+
+            if (e2c != e->e2)
+            {
+                result = new CommaExp(e->loc, e->e1, e2c);
+                result->type = e2c->type;
+            }
+            else
+            {
+                result = e;
+                result->type = e->e2->type;
+            }
+        }
+
+        void visit(SliceExp *e)
+        {
+            //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e->toChars(), e->type->toChars(), t->toChars());
+            Type *typeb = e->type->toBasetype();
+            Type *tb = t->toBasetype();
+            if (e->type->equals(t) || typeb->ty != Tarray ||
+                (tb->ty != Tarray && tb->ty != Tsarray))
+            {
+                visit((Expression *)e);
+                return;
+            }
+
+            if (tb->ty == Tarray)
+            {
+                if (typeb->nextOf()->equivalent(tb->nextOf()))
+                {
+                    // T[] to const(T)[]
+                    result = e->copy();
+                    result->type = t;
+                }
+                else
+                {
+                    visit((Expression *)e);
+                }
+                return;
+            }
+
+            // Handle the cast from Tarray to Tsarray with CT-known slicing
+
+            TypeSArray *tsa = (TypeSArray *)toStaticArrayType(e);
+            if (tsa && tsa->size(e->loc) == tb->size(e->loc))
+            {
+                /* Match if the sarray sizes are equal:
+                 *  T[a .. b] to const(T)[b-a]
+                 *  T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim)
+                 *
+                 * If a SliceExp has Tsarray, it will become lvalue.
+                 * That's handled in SliceExp::isLvalue and toLvalue
+                 */
+                result = e->copy();
+                result->type = t;
+                return;
+            }
+            if (tsa && tsa->dim->equals(((TypeSArray *)tb)->dim))
+            {
+                /* Match if the dimensions are equal
+                 * with the implicit conversion of e->e1:
+                 *  cast(float[2]) [2.0, 1.0, 0.0][0..2];
+                 */
+                Type *t1b = e->e1->type->toBasetype();
+                if (t1b->ty == Tsarray)
+                    t1b = tb->nextOf()->sarrayOf(((TypeSArray *)t1b)->dim->toInteger());
+                else if (t1b->ty == Tarray)
+                    t1b = tb->nextOf()->arrayOf();
+                else if (t1b->ty == Tpointer)
+                    t1b = tb->nextOf()->pointerTo();
+                else
+                    assert(0);
+                if (e->e1->implicitConvTo(t1b) > MATCHnomatch)
+                {
+                    Expression *e1x = e->e1->implicitCastTo(sc, t1b);
+                    assert(e1x->op != TOKerror);
+                    e = (SliceExp *)e->copy();
+                    e->e1 = e1x;
+                    e->type = t;
+                    result = e;
+                    return;
+                }
+            }
+            e->error("cannot cast expression %s of type %s to %s",
+                e->toChars(), tsa ? tsa->toChars() : e->type->toChars(),
+                t->toChars());
+            result = new ErrorExp();
+        }
+    };
+
+    CastTo v(sc, t);
+    e->accept(&v);
+    return v.result;
+}
+
+/* ==================== inferType ====================== */
+
+/****************************************
+ * Set type inference target
+ *      t       Target type
+ *      flag    1: don't put an error when inference fails
+ */
+
+Expression *inferType(Expression *e, Type *t, int flag)
+{
+    class InferType : public Visitor
+    {
+    public:
+        Type *t;
+        int flag;
+        Expression *result;
+
+        InferType(Type *t, int flag)
+            : t(t), flag(flag)
+        {
+            result = NULL;
+        }
+
+
+        void visit(Expression *e)
+        {
+            result = e;
+        }
+
+        void visit(ArrayLiteralExp *ale)
+        {
+            Type *tb = t->toBasetype();
+            if (tb->ty == Tarray || tb->ty == Tsarray)
+            {
+                Type *tn = tb->nextOf();
+                if (ale->basis)
+                    ale->basis = inferType(ale->basis, tn, flag);
+                for (size_t i = 0; i < ale->elements->dim; i++)
+                {
+                    Expression *e = (*ale->elements)[i];
+                    if (e)
+                    {
+                        e = inferType(e, tn, flag);
+                        (*ale->elements)[i] = e;
+                    }
+                }
+            }
+            result = ale;
+        }
+
+        void visit(AssocArrayLiteralExp *aale)
+        {
+            Type *tb = t->toBasetype();
+            if (tb->ty == Taarray)
+            {
+                TypeAArray *taa = (TypeAArray *)tb;
+                Type *ti = taa->index;
+                Type *tv = taa->nextOf();
+                for (size_t i = 0; i < aale->keys->dim; i++)
+                {
+                    Expression *e = (*aale->keys)[i];
+                    if (e)
+                    {
+                        e = inferType(e, ti, flag);
+                        (*aale->keys)[i] = e;
+                    }
+                }
+                for (size_t i = 0; i < aale->values->dim; i++)
+                {
+                    Expression *e = (*aale->values)[i];
+                    if (e)
+                    {
+                        e = inferType(e, tv, flag);
+                        (*aale->values)[i] = e;
+                    }
+                }
+            }
+            result = aale;
+        }
+
+        void visit(FuncExp *fe)
+        {
+            //printf("FuncExp::inferType('%s'), to=%s\n", fe->type ? fe->type->toChars() : "null", t->toChars());
+            if (t->ty == Tdelegate ||
+                t->ty == Tpointer && t->nextOf()->ty == Tfunction)
+            {
+                fe->fd->treq = t;
+            }
+            result = fe;
+        }
+
+        void visit(CondExp *ce)
+        {
+            Type *tb = t->toBasetype();
+            ce->e1 = inferType(ce->e1, tb, flag);
+            ce->e2 = inferType(ce->e2, tb, flag);
+            result = ce;
+        }
+    };
+
+    if (!t)
+        return e;
+
+    InferType v(t, flag);
+    e->accept(&v);
+    return v.result;
+}
+
+/* ==================== ====================== */
+
+/****************************************
+ * Scale addition/subtraction to/from pointer.
+ */
+
+Expression *scaleFactor(BinExp *be, Scope *sc)
+{
+    Type *t1b = be->e1->type->toBasetype();
+    Type *t2b = be->e2->type->toBasetype();
+    Expression *eoff;
+
+    if (t1b->ty == Tpointer && t2b->isintegral())
+    {
+        // Need to adjust operator by the stride
+        // Replace (ptr + int) with (ptr + (int * stride))
+        Type *t = Type::tptrdiff_t;
+
+        d_uns64 stride = t1b->nextOf()->size(be->loc);
+        if (!t->equals(t2b))
+            be->e2 = be->e2->castTo(sc, t);
+        eoff = be->e2;
+        be->e2 = new MulExp(be->loc, be->e2, new IntegerExp(Loc(), stride, t));
+        be->e2->type = t;
+        be->type = be->e1->type;
+    }
+    else if (t2b->ty == Tpointer && t1b->isintegral())
+    {
+        // Need to adjust operator by the stride
+        // Replace (int + ptr) with (ptr + (int * stride))
+        Type *t = Type::tptrdiff_t;
+        Expression *e;
+
+        d_uns64 stride = t2b->nextOf()->size(be->loc);
+        if (!t->equals(t1b))
+            e = be->e1->castTo(sc, t);
+        else
+            e = be->e1;
+        eoff = e;
+        e = new MulExp(be->loc, e, new IntegerExp(Loc(), stride, t));
+        e->type = t;
+        be->type = be->e2->type;
+        be->e1 = be->e2;
+        be->e2 = e;
+    }
+    else
+        assert(0);
+
+    if (sc->func && !sc->intypeof)
+    {
+        eoff = eoff->optimize(WANTvalue);
+        if (eoff->op == TOKint64 && eoff->toInteger() == 0)
+            ;
+        else if (sc->func->setUnsafe())
+        {
+            be->error("pointer arithmetic not allowed in @safe functions");
+            return new ErrorExp();
+        }
+    }
+
+    return be;
+}
+
+/**************************************
+ * Return true if e is an empty array literal with dimensionality
+ * equal to or less than type of other array.
+ * [], [[]], [[[]]], etc.
+ * I.e., make sure that [1,2] is compatible with [],
+ * [[1,2]] is compatible with [[]], etc.
+ */
+bool isVoidArrayLiteral(Expression *e, Type *other)
+{
+    while (e->op == TOKarrayliteral && e->type->ty == Tarray
+        && (((ArrayLiteralExp *)e)->elements->dim == 1))
+    {
+        ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
+        e = ale->getElement(0);
+        if (other->ty == Tsarray || other->ty == Tarray)
+            other = other->nextOf();
+        else
+            return false;
+    }
+    if (other->ty != Tsarray && other->ty != Tarray)
+        return false;
+    Type *t = e->type;
+    return (e->op == TOKarrayliteral && t->ty == Tarray &&
+        t->nextOf()->ty == Tvoid &&
+        ((ArrayLiteralExp *)e)->elements->dim == 0);
+}
+
+// used by deduceType()
+Type *rawTypeMerge(Type *t1, Type *t2)
+{
+    if (t1->equals(t2))
+        return t1;
+    if (t1->equivalent(t2))
+        return t1->castMod(MODmerge(t1->mod, t2->mod));
+
+    Type *t1b = t1->toBasetype();
+    Type *t2b = t2->toBasetype();
+    if (t1b->equals(t2b))
+        return t1b;
+    if (t1b->equivalent(t2b))
+        return t1b->castMod(MODmerge(t1b->mod, t2b->mod));
+
+    TY ty = (TY)impcnvResult[t1b->ty][t2b->ty];
+    if (ty != Terror)
+        return Type::basic[ty];
+
+    return NULL;
+}
+
+/**************************************
+ * Combine types.
+ * Output:
+ *      *pt     merged type, if *pt is not NULL
+ *      *pe1    rewritten e1
+ *      *pe2    rewritten e2
+ * Returns:
+ *      true    success
+ *      false   failed
+ */
+
+bool typeMerge(Scope *sc, TOK op, Type **pt, Expression **pe1, Expression **pe2)
+{
+    //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars());
+
+    MATCH m;
+    Expression *e1 = *pe1;
+    Expression *e2 = *pe2;
+    Type *t1b = e1->type->toBasetype();
+    Type *t2b = e2->type->toBasetype();
+
+    if (op != TOKquestion ||
+        t1b->ty != t2b->ty && (t1b->isTypeBasic() && t2b->isTypeBasic()))
+    {
+        e1 = integralPromotions(e1, sc);
+        e2 = integralPromotions(e2, sc);
+    }
+
+    Type *t1 = e1->type;
+    Type *t2 = e2->type;
+    assert(t1);
+    Type *t = t1;
+
+    /* The start type of alias this type recursion.
+     * In following case, we should save A, and stop recursion
+     * if it appears again.
+     *      X -> Y -> [A] -> B -> A -> B -> ...
+     */
+    Type *att1 = NULL;
+    Type *att2 = NULL;
+
+    //if (t1) printf("\tt1 = %s\n", t1->toChars());
+    //if (t2) printf("\tt2 = %s\n", t2->toChars());
+#ifdef DEBUG
+    if (!t2) printf("\te2 = '%s'\n", e2->toChars());
+#endif
+    assert(t2);
+
+    if (t1->mod != t2->mod &&
+        t1->ty == Tenum && t2->ty == Tenum &&
+        ((TypeEnum *)t1)->sym == ((TypeEnum *)t2)->sym)
+    {
+        unsigned char mod = MODmerge(t1->mod, t2->mod);
+        t1 = t1->castMod(mod);
+        t2 = t2->castMod(mod);
+    }
+
+Lagain:
+    t1b = t1->toBasetype();
+    t2b = t2->toBasetype();
+
+    TY ty = (TY)impcnvResult[t1b->ty][t2b->ty];
+    if (ty != Terror)
+    {
+        TY ty1 = (TY)impcnvType1[t1b->ty][t2b->ty];
+        TY ty2 = (TY)impcnvType2[t1b->ty][t2b->ty];
+
+        if (t1b->ty == ty1)     // if no promotions
+        {
+            if (t1->equals(t2))
+            {
+                t = t1;
+                goto Lret;
+            }
+
+            if (t1b->equals(t2b))
+            {
+                t = t1b;
+                goto Lret;
+            }
+        }
+
+        t = Type::basic[ty];
+
+        t1 = Type::basic[ty1];
+        t2 = Type::basic[ty2];
+        e1 = e1->castTo(sc, t1);
+        e2 = e2->castTo(sc, t2);
+        //printf("after typeCombine():\n");
+        //print();
+        //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2);
+        goto Lret;
+    }
+
+    t1 = t1b;
+    t2 = t2b;
+
+    if (t1->ty == Ttuple || t2->ty == Ttuple)
+        goto Lincompatible;
+
+    if (t1->equals(t2))
+    {
+        // merging can not result in new enum type
+        if (t->ty == Tenum)
+            t = t1b;
+    }
+    else if ((t1->ty == Tpointer && t2->ty == Tpointer) ||
+             (t1->ty == Tdelegate && t2->ty == Tdelegate))
+    {
+        // Bring pointers to compatible type
+        Type *t1n = t1->nextOf();
+        Type *t2n = t2->nextOf();
+
+        if (t1n->equals(t2n))
+            ;
+        else if (t1n->ty == Tvoid)      // pointers to void are always compatible
+            t = t2;
+        else if (t2n->ty == Tvoid)
+            ;
+        else if (t1->implicitConvTo(t2))
+        {
+            goto Lt2;
+        }
+        else if (t2->implicitConvTo(t1))
+        {
+            goto Lt1;
+        }
+        else if (t1n->ty == Tfunction && t2n->ty == Tfunction)
+        {
+            TypeFunction *tf1 = (TypeFunction *)t1n;
+            TypeFunction *tf2 = (TypeFunction *)t2n;
+            tf1->purityLevel();
+            tf2->purityLevel();
+
+            TypeFunction *d = (TypeFunction *)tf1->syntaxCopy();
+
+            if (tf1->purity != tf2->purity)
+                d->purity = PUREimpure;
+            assert(d->purity != PUREfwdref);
+
+            d->isnothrow = (tf1->isnothrow && tf2->isnothrow);
+            d->isnogc    = (tf1->isnogc    && tf2->isnogc);
+
+            if (tf1->trust == tf2->trust)
+                d->trust = tf1->trust;
+            else if (tf1->trust <= TRUSTsystem || tf2->trust <= TRUSTsystem)
+                d->trust = TRUSTsystem;
+            else
+                d->trust = TRUSTtrusted;
+
+            Type *tx = NULL;
+            if (t1->ty == Tdelegate)
+            {
+                tx = new TypeDelegate(d);
+            }
+            else
+                tx = d->pointerTo();
+
+            tx = tx->semantic(e1->loc, sc);
+
+            if (t1->implicitConvTo(tx) && t2->implicitConvTo(tx))
+            {
+                t = tx;
+                e1 = e1->castTo(sc, t);
+                e2 = e2->castTo(sc, t);
+                goto Lret;
+            }
+            goto Lincompatible;
+        }
+        else if (t1n->mod != t2n->mod)
+        {
+            if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared())
+                goto Lincompatible;
+            unsigned char mod = MODmerge(t1n->mod, t2n->mod);
+            t1 = t1n->castMod(mod)->pointerTo();
+            t2 = t2n->castMod(mod)->pointerTo();
+            t = t1;
+            goto Lagain;
+        }
+        else if (t1n->ty == Tclass && t2n->ty == Tclass)
+        {
+            ClassDeclaration *cd1 = t1n->isClassHandle();
+            ClassDeclaration *cd2 = t2n->isClassHandle();
+            int offset;
+
+            if (cd1->isBaseOf(cd2, &offset))
+            {
+                if (offset)
+                    e2 = e2->castTo(sc, t);
+            }
+            else if (cd2->isBaseOf(cd1, &offset))
+            {
+                t = t2;
+                if (offset)
+                    e1 = e1->castTo(sc, t);
+            }
+            else
+                goto Lincompatible;
+        }
+        else
+        {
+            t1 = t1n->constOf()->pointerTo();
+            t2 = t2n->constOf()->pointerTo();
+            if (t1->implicitConvTo(t2))
+            {
+                goto Lt2;
+            }
+            else if (t2->implicitConvTo(t1))
+            {
+                goto Lt1;
+            }
+            goto Lincompatible;
+        }
+    }
+    else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
+             (e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid ||
+              e2->op == TOKarrayliteral && t2->ty == Tsarray && t2->nextOf()->ty == Tvoid && ((TypeSArray *)t2)->dim->toInteger() == 0 ||
+              isVoidArrayLiteral(e2, t1))
+            )
+    {
+        /*  (T[n] op void*)   => T[]
+         *  (T[]  op void*)   => T[]
+         *  (T[n] op void[0]) => T[]
+         *  (T[]  op void[0]) => T[]
+         *  (T[n] op void[])  => T[]
+         *  (T[]  op void[])  => T[]
+         */
+        goto Lx1;
+    }
+    else if ((t2->ty == Tsarray || t2->ty == Tarray) &&
+             (e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid ||
+              e1->op == TOKarrayliteral && t1->ty == Tsarray && t1->nextOf()->ty == Tvoid && ((TypeSArray *)t1)->dim->toInteger() == 0 ||
+              isVoidArrayLiteral(e1, t2))
+            )
+    {
+        /*  (void*   op T[n]) => T[]
+         *  (void*   op T[])  => T[]
+         *  (void[0] op T[n]) => T[]
+         *  (void[0] op T[])  => T[]
+         *  (void[]  op T[n]) => T[]
+         *  (void[]  op T[])  => T[]
+         */
+        goto Lx2;
+    }
+    else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
+             (m = t1->implicitConvTo(t2)) != MATCHnomatch)
+    {
+        // Bugzilla 7285: Tsarray op [x, y, ...] should to be Tsarray
+        // Bugzilla 14737: Tsarray ~ [x, y, ...] should to be Tarray
+        if (t1->ty == Tsarray && e2->op == TOKarrayliteral && op != TOKcat)
+            goto Lt1;
+        if (m == MATCHconst &&
+            (op == TOKaddass || op == TOKminass || op == TOKmulass ||
+             op == TOKdivass || op == TOKmodass || op == TOKpowass ||
+             op == TOKandass || op == TOKorass  || op == TOKxorass)
+           )
+        {
+            // Don't make the lvalue const
+            t = t2;
+            goto Lret;
+        }
+        goto Lt2;
+    }
+    else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1))
+    {
+        // Bugzilla 7285 & 14737
+        if (t2->ty == Tsarray && e1->op == TOKarrayliteral && op != TOKcat)
+            goto Lt2;
+        goto Lt1;
+    }
+    else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) &&
+             (t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) &&
+             t1->nextOf()->mod != t2->nextOf()->mod
+            )
+    {
+        /* If one is mutable and the other invariant, then retry
+         * with both of them as const
+         */
+        Type *t1n = t1->nextOf();
+        Type *t2n = t2->nextOf();
+        unsigned char mod;
+        if (e1->op == TOKnull && e2->op != TOKnull)
+            mod = t2n->mod;
+        else if (e1->op != TOKnull && e2->op == TOKnull)
+            mod = t1n->mod;
+        else if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared())
+            goto Lincompatible;
+        else
+            mod = MODmerge(t1n->mod, t2n->mod);
+
+        if (t1->ty == Tpointer)
+            t1 = t1n->castMod(mod)->pointerTo();
+        else
+            t1 = t1n->castMod(mod)->arrayOf();
+
+        if (t2->ty == Tpointer)
+            t2 = t2n->castMod(mod)->pointerTo();
+        else
+            t2 = t2n->castMod(mod)->arrayOf();
+        t = t1;
+        goto Lagain;
+    }
+    else if (t1->ty == Tclass && t2->ty == Tclass)
+    {
+        if (t1->mod != t2->mod)
+        {
+            unsigned char mod;
+            if (e1->op == TOKnull && e2->op != TOKnull)
+                mod = t2->mod;
+            else if (e1->op != TOKnull && e2->op == TOKnull)
+                mod = t1->mod;
+            else if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
+                goto Lincompatible;
+            else
+                mod = MODmerge(t1->mod, t2->mod);
+            t1 = t1->castMod(mod);
+            t2 = t2->castMod(mod);
+            t = t1;
+            goto Lagain;
+        }
+        goto Lcc;
+    }
+    else if (t1->ty == Tclass || t2->ty == Tclass)
+    {
+Lcc:
+        while (1)
+        {
+            MATCH i1 = e2->implicitConvTo(t1);
+            MATCH i2 = e1->implicitConvTo(t2);
+
+            if (i1 && i2)
+            {
+                // We have the case of class vs. void*, so pick class
+                if (t1->ty == Tpointer)
+                    i1 = MATCHnomatch;
+                else if (t2->ty == Tpointer)
+                    i2 = MATCHnomatch;
+            }
+
+            if (i2)
+            {
+                e2 = e2->castTo(sc, t2);
+                goto Lt2;
+            }
+            else if (i1)
+            {
+                e1 = e1->castTo(sc, t1);
+                goto Lt1;
+            }
+            else if (t1->ty == Tclass && t2->ty == Tclass)
+            {
+                TypeClass *tc1 = (TypeClass *)t1;
+                TypeClass *tc2 = (TypeClass *)t2;
+
+                /* Pick 'tightest' type
+                 */
+                ClassDeclaration *cd1 = tc1->sym->baseClass;
+                ClassDeclaration *cd2 = tc2->sym->baseClass;
+
+                if (cd1 && cd2)
+                {
+                    t1 = cd1->type;
+                    t2 = cd2->type;
+                }
+                else if (cd1)
+                    t1 = cd1->type;
+                else if (cd2)
+                    t2 = cd2->type;
+                else
+                    goto Lincompatible;
+            }
+            else if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis)
+            {
+                if (att1 && e1->type == att1)
+                    goto Lincompatible;
+                if (!att1 && e1->type->checkAliasThisRec())
+                    att1 = e1->type;
+                //printf("att tmerge(c || c) e1 = %s\n", e1->type->toChars());
+                e1 = resolveAliasThis(sc, e1);
+                t1 = e1->type;
+                continue;
+            }
+            else if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis)
+            {
+                if (att2 && e2->type == att2)
+                    goto Lincompatible;
+                if (!att2 && e2->type->checkAliasThisRec())
+                    att2 = e2->type;
+                //printf("att tmerge(c || c) e2 = %s\n", e2->type->toChars());
+                e2 = resolveAliasThis(sc, e2);
+                t2 = e2->type;
+                continue;
+            }
+            else
+                goto Lincompatible;
+        }
+    }
+    else if (t1->ty == Tstruct && t2->ty == Tstruct)
+    {
+        if (t1->mod != t2->mod)
+        {
+            if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
+                goto Lincompatible;
+            unsigned char mod = MODmerge(t1->mod, t2->mod);
+            t1 = t1->castMod(mod);
+            t2 = t2->castMod(mod);
+            t = t1;
+            goto Lagain;
+        }
+
+        TypeStruct *ts1 = (TypeStruct *)t1;
+        TypeStruct *ts2 = (TypeStruct *)t2;
+        if (ts1->sym != ts2->sym)
+        {
+            if (!ts1->sym->aliasthis && !ts2->sym->aliasthis)
+                goto Lincompatible;
+
+            MATCH i1 = MATCHnomatch;
+            MATCH i2 = MATCHnomatch;
+
+            Expression *e1b = NULL;
+            Expression *e2b = NULL;
+            if (ts2->sym->aliasthis)
+            {
+                if (att2 && e2->type == att2)
+                    goto Lincompatible;
+                if (!att2 && e2->type->checkAliasThisRec())
+                    att2 = e2->type;
+                //printf("att tmerge(s && s) e2 = %s\n", e2->type->toChars());
+                e2b = resolveAliasThis(sc, e2);
+                i1 = e2b->implicitConvTo(t1);
+            }
+            if (ts1->sym->aliasthis)
+            {
+                if (att1 && e1->type == att1)
+                    goto Lincompatible;
+                if (!att1 && e1->type->checkAliasThisRec())
+                    att1 = e1->type;
+                //printf("att tmerge(s && s) e1 = %s\n", e1->type->toChars());
+                e1b = resolveAliasThis(sc, e1);
+                i2 = e1b->implicitConvTo(t2);
+            }
+            if (i1 && i2)
+                goto Lincompatible;
+
+            if (i1)
+                goto Lt1;
+            else if (i2)
+                goto Lt2;
+
+            if (e1b)
+            {
+                e1 = e1b;
+                t1 = e1b->type->toBasetype();
+            }
+            if (e2b)
+            {
+                e2 = e2b;
+                t2 = e2b->type->toBasetype();
+            }
+            t = t1;
+            goto Lagain;
+        }
+    }
+    else if (t1->ty == Tstruct || t2->ty == Tstruct)
+    {
+        if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis)
+        {
+            if (att1 && e1->type == att1)
+                goto Lincompatible;
+            if (!att1 && e1->type->checkAliasThisRec())
+                att1 = e1->type;
+            //printf("att tmerge(s || s) e1 = %s\n", e1->type->toChars());
+            e1 = resolveAliasThis(sc, e1);
+            t1 = e1->type;
+            t = t1;
+            goto Lagain;
+        }
+        if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis)
+        {
+            if (att2 && e2->type == att2)
+                goto Lincompatible;
+            if (!att2 && e2->type->checkAliasThisRec())
+                att2 = e2->type;
+            //printf("att tmerge(s || s) e2 = %s\n", e2->type->toChars());
+            e2 = resolveAliasThis(sc, e2);
+            t2 = e2->type;
+            t = t2;
+            goto Lagain;
+        }
+        goto Lincompatible;
+    }
+    else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2))
+    {
+        goto Lt2;
+    }
+    else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1))
+    {
+        goto Lt1;
+    }
+    else if (t1->ty == Tsarray && t2->ty == Tsarray &&
+             e2->implicitConvTo(t1->nextOf()->arrayOf()))
+    {
+     Lx1:
+        t = t1->nextOf()->arrayOf();    // T[]
+        e1 = e1->castTo(sc, t);
+        e2 = e2->castTo(sc, t);
+    }
+    else if (t1->ty == Tsarray && t2->ty == Tsarray &&
+             e1->implicitConvTo(t2->nextOf()->arrayOf()))
+    {
+     Lx2:
+        t = t2->nextOf()->arrayOf();
+        e1 = e1->castTo(sc, t);
+        e2 = e2->castTo(sc, t);
+    }
+    else if (t1->ty == Tvector && t2->ty == Tvector)
+    {
+        // Bugzilla 13841, all vector types should have no common types between
+        // different vectors, even though their sizes are same.
+        TypeVector *tv1 = (TypeVector *)t1;
+        TypeVector *tv2 = (TypeVector *)t2;
+        if (!tv1->basetype->equals(tv2->basetype))
+            goto Lincompatible;
+
+        goto LmodCompare;
+    }
+    else if (t1->ty == Tvector && t2->ty != Tvector &&
+             e2->implicitConvTo(t1))
+    {
+        e2 = e2->castTo(sc, t1);
+        t2 = t1;
+        t = t1;
+        goto Lagain;
+    }
+    else if (t2->ty == Tvector && t1->ty != Tvector &&
+             e1->implicitConvTo(t2))
+    {
+        e1 = e1->castTo(sc, t2);
+        t1 = t2;
+        t = t1;
+        goto Lagain;
+    }
+    else if (t1->isintegral() && t2->isintegral())
+    {
+        if (t1->ty != t2->ty)
+        {
+            if (t1->ty == Tvector || t2->ty == Tvector)
+                goto Lincompatible;
+            e1 = integralPromotions(e1, sc);
+            e2 = integralPromotions(e2, sc);
+            t1 = e1->type;
+            t2 = e2->type;
+            goto Lagain;
+        }
+        assert(t1->ty == t2->ty);
+LmodCompare:
+        if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
+            goto Lincompatible;
+        unsigned char mod = MODmerge(t1->mod, t2->mod);
+
+        t1 = t1->castMod(mod);
+        t2 = t2->castMod(mod);
+        t = t1;
+        e1 = e1->castTo(sc, t);
+        e2 = e2->castTo(sc, t);
+        goto Lagain;
+    }
+    else if (t1->ty == Tnull && t2->ty == Tnull)
+    {
+        unsigned char mod = MODmerge(t1->mod, t2->mod);
+
+        t = t1->castMod(mod);
+        e1 = e1->castTo(sc, t);
+        e2 = e2->castTo(sc, t);
+        goto Lret;
+    }
+    else if (t2->ty == Tnull &&
+        (t1->ty == Tpointer || t1->ty == Taarray || t1->ty == Tarray))
+    {
+        goto Lt1;
+    }
+    else if (t1->ty == Tnull &&
+        (t2->ty == Tpointer || t2->ty == Taarray || t2->ty == Tarray))
+    {
+        goto Lt2;
+    }
+    else if (t1->ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1))
+    {
+        if (e2->implicitConvTo(t1->nextOf()))
+        {
+            // T[] op T
+            // T[] op cast(T)U
+            e2 = e2->castTo(sc, t1->nextOf());
+            t = t1->nextOf()->arrayOf();
+        }
+        else if (t1->nextOf()->implicitConvTo(e2->type))
+        {
+            // (cast(T)U)[] op T    (Bugzilla 12780)
+            // e1 is left as U[], it will be handled in arrayOp() later.
+            t = e2->type->arrayOf();
+        }
+        else if (t2->ty == Tarray && isArrayOpOperand(e2))
+        {
+            if (t1->nextOf()->implicitConvTo(t2->nextOf()))
+            {
+                // (cast(T)U)[] op T[]  (Bugzilla 12780)
+                // e1 is left as U[], it will be handled in arrayOp() later.
+                t = t2->nextOf()->arrayOf();
+            }
+            else if (t2->nextOf()->implicitConvTo(t1->nextOf()))
+            {
+                // T[] op (cast(T)U)[]  (Bugzilla 12780)
+                // e2 is left as U[], it will be handled in arrayOp() later.
+                t = t1->nextOf()->arrayOf();
+            }
+            else
+                goto Lincompatible;
+        }
+        else
+            goto Lincompatible;
+    }
+    else if (t2->ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e2))
+    {
+        if (e1->implicitConvTo(t2->nextOf()))
+        {
+            // T op T[]
+            // cast(T)U op T[]
+            e1 = e1->castTo(sc, t2->nextOf());
+            t = t2->nextOf()->arrayOf();
+        }
+        else if (t2->nextOf()->implicitConvTo(e1->type))
+        {
+            // T op (cast(T)U)[]    (Bugzilla 12780)
+            // e2 is left as U[], it will be handled in arrayOp() later.
+            t = e1->type->arrayOf();
+        }
+        else
+            goto Lincompatible;
+
+        //printf("test %s\n", Token::toChars(op));
+        e1 = e1->optimize(WANTvalue);
+        if (isCommutative(op) && e1->isConst())
+        {
+            /* Swap operands to minimize number of functions generated
+             */
+            //printf("swap %s\n", Token::toChars(op));
+            Expression *tmp = e1;
+            e1 = e2;
+            e2 = tmp;
+        }
+    }
+    else
+    {
+    Lincompatible:
+        return false;
+    }
+Lret:
+    if (!*pt)
+        *pt = t;
+    *pe1 = e1;
+    *pe2 = e2;
+#if 0
+    printf("-typeMerge() %s op %s\n", e1->toChars(), e2->toChars());
+    if (e1->type) printf("\tt1 = %s\n", e1->type->toChars());
+    if (e2->type) printf("\tt2 = %s\n", e2->type->toChars());
+    printf("\ttype = %s\n", t->toChars());
+#endif
+    //print();
+    return true;
+
+
+Lt1:
+    e2 = e2->castTo(sc, t1);
+    t = t1;
+    goto Lret;
+
+Lt2:
+    e1 = e1->castTo(sc, t2);
+    t = t2;
+    goto Lret;
+}
+
+/************************************
+ * Bring leaves to common type.
+ * Returns ErrorExp if error occurs. otherwise returns NULL.
+ */
+
+Expression *typeCombine(BinExp *be, Scope *sc)
+{
+    Type *t1 = be->e1->type->toBasetype();
+    Type *t2 = be->e2->type->toBasetype();
+
+    if (be->op == TOKmin || be->op == TOKadd)
+    {
+        // struct+struct, and class+class are errors
+        if (t1->ty == Tstruct && t2->ty == Tstruct)
+            goto Lerror;
+        else if (t1->ty == Tclass && t2->ty == Tclass)
+            goto Lerror;
+        else if (t1->ty == Taarray && t2->ty == Taarray)
+            goto Lerror;
+    }
+
+    if (!typeMerge(sc, be->op, &be->type, &be->e1, &be->e2))
+        goto Lerror;
+    // If the types have no value, return an error
+    if (be->e1->op == TOKerror)
+        return be->e1;
+    if (be->e2->op == TOKerror)
+        return be->e2;
+    return NULL;
+
+Lerror:
+    Expression *ex = be->incompatibleTypes();
+    if (ex->op == TOKerror)
+        return ex;
+    return new ErrorExp();
+}
+
+/***********************************
+ * Do integral promotions (convertchk).
+ * Don't convert <array of> to <pointer to>
+ */
+
+Expression *integralPromotions(Expression *e, Scope *sc)
+{
+    //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars());
+    switch (e->type->toBasetype()->ty)
+    {
+        case Tvoid:
+            e->error("void has no value");
+            return new ErrorExp();
+
+        case Tint8:
+        case Tuns8:
+        case Tint16:
+        case Tuns16:
+        case Tbool:
+        case Tchar:
+        case Twchar:
+            e = e->castTo(sc, Type::tint32);
+            break;
+
+        case Tdchar:
+            e = e->castTo(sc, Type::tuns32);
+            break;
+        default:
+            break;
+    }
+    return e;
+}
+
+/***********************************
+ * See if both types are arrays that can be compared
+ * for equality. Return true if so.
+ * If they are arrays, but incompatible, issue error.
+ * This is to enable comparing things like an immutable
+ * array with a mutable one.
+ */
+
+bool arrayTypeCompatible(Loc loc, Type *t1, Type *t2)
+{
+    t1 = t1->toBasetype()->merge2();
+    t2 = t2->toBasetype()->merge2();
+
+    if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
+        (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer))
+    {
+        if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst &&
+            t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst &&
+            (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid))
+        {
+            error(loc, "array equality comparison type mismatch, %s vs %s", t1->toChars(), t2->toChars());
+        }
+        return true;
+    }
+    return false;
+}
+
+/***********************************
+ * See if both types are arrays that can be compared
+ * for equality without any casting. Return true if so.
+ * This is to enable comparing things like an immutable
+ * array with a mutable one.
+ */
+bool arrayTypeCompatibleWithoutCasting(Loc loc, Type *t1, Type *t2)
+{
+    t1 = t1->toBasetype();
+    t2 = t2->toBasetype();
+
+    if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
+        t2->ty == t1->ty)
+    {
+        if (t1->nextOf()->implicitConvTo(t2->nextOf()) >= MATCHconst ||
+            t2->nextOf()->implicitConvTo(t1->nextOf()) >= MATCHconst)
+            return true;
+    }
+    return false;
+}
+
+/******************************************************************/
+
+/* Determine the integral ranges of an expression.
+ * This is used to determine if implicit narrowing conversions will
+ * be allowed.
+ */
+
+IntRange getIntRange(Expression *e)
+{
+    class IntRangeVisitor : public Visitor
+    {
+    private:
+        static uinteger_t getMask(uinteger_t v)
+        {
+            // Ref: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+            v |= v >> 1;
+            v |= v >> 2;
+            v |= v >> 4;
+            v |= v >> 8;
+            v |= v >> 16;
+            v |= v >> 32;
+            return v;
+        }
+
+        // The algorithms for &, |, ^ are not yet the best! Sometimes they will produce
+        //  not the tightest bound. See
+        //      https://github.com/D-Programming-Language/dmd/pull/116
+        //  for detail.
+        static IntRange unsignedBitwiseAnd(const IntRange& a, const IntRange& b)
+        {
+            // the DiffMasks stores the mask of bits which are variable in the range.
+            uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
+            uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
+            // Since '&' computes the digitwise-minimum, the we could set all varying
+            //  digits to 0 to get a lower bound, and set all varying digits to 1 to get
+            //  an upper bound.
+            IntRange result;
+            result.imin.value = (a.imin.value & ~aDiffMask) & (b.imin.value & ~bDiffMask);
+            result.imax.value = (a.imax.value | aDiffMask) & (b.imax.value | bDiffMask);
+            // Sometimes the upper bound is overestimated. The upper bound will never
+            //  exceed the input.
+            if (result.imax.value > a.imax.value)
+                result.imax.value = a.imax.value;
+            if (result.imax.value > b.imax.value)
+                result.imax.value = b.imax.value;
+            result.imin.negative = result.imax.negative = a.imin.negative && b.imin.negative;
+            return result;
+        }
+        static IntRange unsignedBitwiseOr(const IntRange& a, const IntRange& b)
+        {
+            // the DiffMasks stores the mask of bits which are variable in the range.
+            uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
+            uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
+            // The imax algorithm by Adam D. Ruppe.
+            // http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=108796
+            IntRange result;
+            result.imin.value = (a.imin.value & ~aDiffMask) | (b.imin.value & ~bDiffMask);
+            result.imax.value = a.imax.value | b.imax.value | getMask(a.imax.value & b.imax.value);
+            // Sometimes the lower bound is underestimated. The lower bound will never
+            //  less than the input.
+            if (result.imin.value < a.imin.value)
+                result.imin.value = a.imin.value;
+            if (result.imin.value < b.imin.value)
+                result.imin.value = b.imin.value;
+            result.imin.negative = result.imax.negative = a.imin.negative || b.imin.negative;
+            return result;
+        }
+        static IntRange unsignedBitwiseXor(const IntRange& a, const IntRange& b)
+        {
+            // the DiffMasks stores the mask of bits which are variable in the range.
+            uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
+            uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
+            IntRange result;
+            result.imin.value = (a.imin.value ^ b.imin.value) & ~(aDiffMask | bDiffMask);
+            result.imax.value = (a.imax.value ^ b.imax.value) | (aDiffMask | bDiffMask);
+            result.imin.negative = result.imax.negative = a.imin.negative != b.imin.negative;
+            return result;
+        }
+
+    public:
+        IntRange range;
+
+        void visit(Expression *e)
+        {
+            range = IntRange::fromType(e->type);
+        }
+
+        void visit(IntegerExp *e)
+        {
+            range = IntRange(SignExtendedNumber(e->getInteger())).cast(e->type);
+        }
+
+        void visit(CastExp *e)
+        {
+            range = getIntRange(e->e1).cast(e->type);
+        }
+
+        void visit(AddExp *e)
+        {
+            IntRange ir1 = getIntRange(e->e1);
+            IntRange ir2 = getIntRange(e->e2);
+            range = IntRange(ir1.imin + ir2.imin, ir1.imax + ir2.imax).cast(e->type);
+        }
+
+        void visit(MinExp *e)
+        {
+            IntRange ir1 = getIntRange(e->e1);
+            IntRange ir2 = getIntRange(e->e2);
+            range = IntRange(ir1.imin - ir2.imax, ir1.imax - ir2.imin).cast(e->type);
+        }
+
+        void visit(DivExp *e)
+        {
+            IntRange ir1 = getIntRange(e->e1);
+            IntRange ir2 = getIntRange(e->e2);
+
+            // Should we ignore the possibility of div-by-0???
+            if (ir2.containsZero())
+            {
+                visit((Expression *)e);
+                return;
+            }
+
+            // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
+            SignExtendedNumber bdy[4];
+            bdy[0] = ir1.imin / ir2.imin;
+            bdy[1] = ir1.imin / ir2.imax;
+            bdy[2] = ir1.imax / ir2.imin;
+            bdy[3] = ir1.imax / ir2.imax;
+            range = IntRange::fromNumbers4(bdy).cast(e->type);
+        }
+
+        void visit(MulExp *e)
+        {
+            IntRange ir1 = getIntRange(e->e1);
+            IntRange ir2 = getIntRange(e->e2);
+
+            // [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)]
+            SignExtendedNumber bdy[4];
+            bdy[0] = ir1.imin * ir2.imin;
+            bdy[1] = ir1.imin * ir2.imax;
+            bdy[2] = ir1.imax * ir2.imin;
+            bdy[3] = ir1.imax * ir2.imax;
+            range = IntRange::fromNumbers4(bdy).cast(e->type);
+        }
+
+        void visit(ModExp *e)
+        {
+            IntRange irNum = getIntRange(e->e1);
+            IntRange irDen = getIntRange(e->e2).absNeg();
+
+            /*
+            due to the rules of D (C)'s % operator, we need to consider the cases
+            separately in different range of signs.
+
+                case 1. [500, 1700] % [7, 23] (numerator is always positive)
+                    = [0, 22]
+                case 2. [-500, 1700] % [7, 23] (numerator can be negative)
+                    = [-22, 22]
+                case 3. [-1700, -500] % [7, 23] (numerator is always negative)
+                    = [-22, 0]
+
+            the number 22 is the maximum absolute value in the denomator's range. We
+            don't care about divide by zero.
+            */
+
+            // Modding on 0 is invalid anyway.
+            if (!irDen.imin.negative)
+            {
+                visit((Expression *)e);
+                return;
+            }
+
+            ++ irDen.imin;
+            irDen.imax = -irDen.imin;
+
+            if (!irNum.imin.negative)
+                irNum.imin.value = 0;
+            else if (irNum.imin < irDen.imin)
+                irNum.imin = irDen.imin;
+
+            if (irNum.imax.negative)
+            {
+                irNum.imax.negative = false;
+                irNum.imax.value = 0;
+            }
+            else if (irNum.imax > irDen.imax)
+                irNum.imax = irDen.imax;
+
+            range = irNum.cast(e->type);
+        }
+
+        void visit(AndExp *e)
+        {
+            IntRange ir1 = getIntRange(e->e1);
+            IntRange ir2 = getIntRange(e->e2);
+
+            IntRange ir1neg, ir1pos, ir2neg, ir2pos;
+            bool has1neg, has1pos, has2neg, has2pos;
+
+            ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
+            ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
+
+            IntRange result;
+            bool hasResult = false;
+            if (has1pos && has2pos)
+                result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2pos), hasResult);
+            if (has1pos && has2neg)
+                result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2neg), hasResult);
+            if (has1neg && has2pos)
+                result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2pos), hasResult);
+            if (has1neg && has2neg)
+                result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2neg), hasResult);
+            assert(hasResult);
+            range = result.cast(e->type);
+        }
+
+        void visit(OrExp *e)
+        {
+            IntRange ir1 = getIntRange(e->e1);
+            IntRange ir2 = getIntRange(e->e2);
+
+            IntRange ir1neg, ir1pos, ir2neg, ir2pos;
+            bool has1neg, has1pos, has2neg, has2pos;
+
+            ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
+            ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
+
+            IntRange result;
+            bool hasResult = false;
+            if (has1pos && has2pos)
+                result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2pos), hasResult);
+            if (has1pos && has2neg)
+                result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2neg), hasResult);
+            if (has1neg && has2pos)
+                result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2pos), hasResult);
+            if (has1neg && has2neg)
+                result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2neg), hasResult);
+
+            assert(hasResult);
+            range = result.cast(e->type);
+        }
+
+        void visit(XorExp *e)
+        {
+            IntRange ir1 = getIntRange(e->e1);
+            IntRange ir2 = getIntRange(e->e2);
+
+            IntRange ir1neg, ir1pos, ir2neg, ir2pos;
+            bool has1neg, has1pos, has2neg, has2pos;
+
+            ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
+            ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
+
+            IntRange result;
+            bool hasResult = false;
+            if (has1pos && has2pos)
+                result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2pos), hasResult);
+            if (has1pos && has2neg)
+                result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2neg), hasResult);
+            if (has1neg && has2pos)
+                result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2pos), hasResult);
+            if (has1neg && has2neg)
+                result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2neg), hasResult);
+
+            assert(hasResult);
+            range = result.cast(e->type);
+        }
+
+        void visit(ShlExp *e)
+        {
+            IntRange ir1 = getIntRange(e->e1);
+            IntRange ir2 = getIntRange(e->e2);
+
+            if (ir2.imin.negative)
+                ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
+
+            SignExtendedNumber lower = ir1.imin << (ir1.imin.negative ? ir2.imax : ir2.imin);
+            SignExtendedNumber upper = ir1.imax << (ir1.imax.negative ? ir2.imin : ir2.imax);
+
+            range = IntRange(lower, upper).cast(e->type);
+        }
+
+        void visit(ShrExp *e)
+        {
+            IntRange ir1 = getIntRange(e->e1);
+            IntRange ir2 = getIntRange(e->e2);
+
+            if (ir2.imin.negative)
+                ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
+
+            SignExtendedNumber lower = ir1.imin >> (ir1.imin.negative ? ir2.imin : ir2.imax);
+            SignExtendedNumber upper = ir1.imax >> (ir1.imax.negative ? ir2.imax : ir2.imin);
+
+            range = IntRange(lower, upper).cast(e->type);
+        }
+
+        void visit(UshrExp *e)
+        {
+            IntRange ir1 = getIntRange(e->e1).castUnsigned(e->e1->type);
+            IntRange ir2 = getIntRange(e->e2);
+
+            if (ir2.imin.negative)
+                ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
+
+            range = IntRange(ir1.imin >> ir2.imax, ir1.imax >> ir2.imin).cast(e->type);
+        }
+
+        void visit(AssignExp *e)
+        {
+            range = getIntRange(e->e2).cast(e->type);
+        }
+
+        void visit(CondExp *e)
+        {
+            // No need to check e->econd; assume caller has called optimize()
+            IntRange ir1 = getIntRange(e->e1);
+            IntRange ir2 = getIntRange(e->e2);
+            range = ir1.unionWith(ir2).cast(e->type);
+        }
+
+        void visit(VarExp *e)
+        {
+            Expression *ie;
+            VarDeclaration* vd = e->var->isVarDeclaration();
+            if (vd && vd->range)
+                range = vd->range->cast(e->type);
+            else if (vd && vd->_init && !vd->type->isMutable() &&
+                (ie = vd->getConstInitializer()) != NULL)
+                ie->accept(this);
+            else
+                visit((Expression *)e);
+        }
+
+        void visit(CommaExp *e)
+        {
+            e->e2->accept(this);
+        }
+
+        void visit(ComExp *e)
+        {
+            IntRange ir = getIntRange(e->e1);
+            range = IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative),
+                            SignExtendedNumber(~ir.imin.value, !ir.imin.negative)).cast(e->type);
+        }
+
+        void visit(NegExp *e)
+        {
+            IntRange ir = getIntRange(e->e1);
+            range = IntRange(-ir.imax, -ir.imin).cast(e->type);
+        }
+    };
+
+    IntRangeVisitor v;
+    e->accept(&v);
+    return v.range;
+}
diff --git a/gcc/d/dfrontend/dclass.c b/gcc/d/dfrontend/dclass.c
new file mode 100644
index 00000000000..70c893c66f4
--- /dev/null
+++ b/gcc/d/dfrontend/dclass.c
@@ -0,0 +1,1947 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/class.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>                     // mem{cpy|set}()
+
+#include "root.h"
+#include "rmem.h"
+
+#include "enum.h"
+#include "init.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+#include "mtype.h"
+#include "scope.h"
+#include "module.h"
+#include "expression.h"
+#include "statement.h"
+#include "template.h"
+#include "target.h"
+#include "objc.h"
+
+bool symbolIsVisible(Dsymbol *origin, Dsymbol *s);
+Objc *objc();
+
+
+/********************************* ClassDeclaration ****************************/
+
+ClassDeclaration *ClassDeclaration::object;
+ClassDeclaration *ClassDeclaration::throwable;
+ClassDeclaration *ClassDeclaration::exception;
+ClassDeclaration *ClassDeclaration::errorException;
+ClassDeclaration *ClassDeclaration::cpp_type_info_ptr;   // Object.__cpp_type_info_ptr
+
+ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject)
+    : AggregateDeclaration(loc, id ? id : Identifier::generateId("__anonclass"))
+{
+    static const char msg[] = "only object.d can define this reserved class name";
+
+    if (baseclasses)
+    {
+        // Actually, this is a transfer
+        this->baseclasses = baseclasses;
+    }
+    else
+        this->baseclasses = new BaseClasses();
+
+    this->members = members;
+
+    baseClass = NULL;
+
+    interfaces.length = 0;
+    interfaces.ptr = NULL;
+
+    vtblInterfaces = NULL;
+
+    //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses->dim);
+
+    // For forward references
+    type = new TypeClass(this);
+
+    staticCtor = NULL;
+    staticDtor = NULL;
+
+    vtblsym = NULL;
+    vclassinfo = NULL;
+
+    if (id)
+    {
+        // Look for special class names
+
+        if (id == Id::__sizeof || id == Id::__xalignof || id == Id::_mangleof)
+            error("illegal class name");
+
+        // BUG: What if this is the wrong TypeInfo, i.e. it is nested?
+        if (id->toChars()[0] == 'T')
+        {
+            if (id == Id::TypeInfo)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::dtypeinfo = this;
+            }
+
+            if (id == Id::TypeInfo_Class)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfoclass = this;
+            }
+
+            if (id == Id::TypeInfo_Interface)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfointerface = this;
+            }
+
+            if (id == Id::TypeInfo_Struct)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfostruct = this;
+            }
+
+            if (id == Id::TypeInfo_Pointer)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfopointer = this;
+            }
+
+            if (id == Id::TypeInfo_Array)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfoarray = this;
+            }
+
+            if (id == Id::TypeInfo_StaticArray)
+            {
+                //if (!inObject)
+                //    Type::typeinfostaticarray->error("%s", msg);
+                Type::typeinfostaticarray = this;
+            }
+
+            if (id == Id::TypeInfo_AssociativeArray)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfoassociativearray = this;
+            }
+
+            if (id == Id::TypeInfo_Enum)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfoenum = this;
+            }
+
+            if (id == Id::TypeInfo_Function)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfofunction = this;
+            }
+
+            if (id == Id::TypeInfo_Delegate)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfodelegate = this;
+            }
+
+            if (id == Id::TypeInfo_Tuple)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfotypelist = this;
+            }
+
+            if (id == Id::TypeInfo_Const)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfoconst = this;
+            }
+
+            if (id == Id::TypeInfo_Invariant)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfoinvariant = this;
+            }
+
+            if (id == Id::TypeInfo_Shared)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfoshared = this;
+            }
+
+            if (id == Id::TypeInfo_Wild)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfowild = this;
+            }
+
+            if (id == Id::TypeInfo_Vector)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type::typeinfovector = this;
+            }
+        }
+
+        if (id == Id::Object)
+        {
+            if (!inObject)
+                error("%s", msg);
+            object = this;
+        }
+
+        if (id == Id::Throwable)
+        {
+            if (!inObject)
+                error("%s", msg);
+            throwable = this;
+        }
+
+        if (id == Id::Exception)
+        {
+            if (!inObject)
+                error("%s", msg);
+            exception = this;
+        }
+
+        if (id == Id::Error)
+        {
+            if (!inObject)
+                error("%s", msg);
+            errorException = this;
+        }
+
+        if (id == Id::cpp_type_info_ptr)
+        {
+            if (!inObject)
+                error("%s", msg);
+            cpp_type_info_ptr = this;
+        }
+    }
+
+    com = false;
+    cpp = false;
+    isscope = false;
+    isabstract = ABSfwdref;
+    inuse = 0;
+    baseok = BASEOKnone;
+    isobjc = false;
+    cpp_type_info_ptr_sym = NULL;
+}
+
+ClassDeclaration *ClassDeclaration::create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject)
+{
+    return new ClassDeclaration(loc, id, baseclasses, members, inObject);
+}
+
+Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars());
+    ClassDeclaration *cd =
+        s ? (ClassDeclaration *)s
+          : new ClassDeclaration(loc, ident, NULL, NULL, false);
+
+    cd->storage_class |= storage_class;
+
+    cd->baseclasses->setDim(this->baseclasses->dim);
+    for (size_t i = 0; i < cd->baseclasses->dim; i++)
+    {
+        BaseClass *b = (*this->baseclasses)[i];
+        BaseClass *b2 = new BaseClass(b->type->syntaxCopy());
+        (*cd->baseclasses)[i] = b2;
+    }
+
+    return ScopeDsymbol::syntaxCopy(cd);
+}
+
+Scope *ClassDeclaration::newScope(Scope *sc)
+{
+    Scope *sc2 = AggregateDeclaration::newScope(sc);
+    if (isCOMclass())
+    {
+        if (global.params.isWindows)
+            sc2->linkage = LINKwindows;
+        else
+        {
+            /* This enables us to use COM objects under Linux and
+             * work with things like XPCOM
+             */
+            sc2->linkage = LINKc;
+        }
+    }
+    return sc2;
+}
+
+/* Bugzilla 12078, 12143 and 15733:
+ * While resolving base classes and interfaces, a base may refer
+ * the member of this derived class. In that time, if all bases of
+ * this class can  be determined, we can go forward the semantc process
+ * beyond the Lancestorsdone. To do the recursive semantic analysis,
+ * temporarily set and unset `_scope` around exp().
+ */
+static Type *resolveBase(ClassDeclaration *cd, Scope *sc, Scope *&scx, Type *type)
+{
+    if (!scx)
+    {
+        scx = sc->copy();
+        scx->setNoFree();
+    }
+    cd->_scope = scx;
+    Type *t = type->semantic(cd->loc, sc);
+    cd->_scope = NULL;
+    return t;
+}
+
+static void resolveBase(ClassDeclaration *cd, Scope *sc, Scope *&scx, ClassDeclaration *sym)
+{
+    if (!scx)
+    {
+        scx = sc->copy();
+        scx->setNoFree();
+    }
+    cd->_scope = scx;
+    sym->semantic(NULL);
+    cd->_scope = NULL;
+}
+
+static void badObjectDotD(ClassDeclaration *cd)
+{
+    cd->error("missing or corrupt object.d");
+    fatal();
+}
+
+void ClassDeclaration::semantic(Scope *sc)
+{
+    //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
+    //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : "");
+    //printf("sc->stc = %x\n", sc->stc);
+
+    //{ static int n;  if (++n == 20) *(char*)0=0; }
+
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    int errors = global.errors;
+
+    //printf("+ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
+
+    Scope *scx = NULL;
+    if (_scope)
+    {
+        sc = _scope;
+        scx = _scope;            // save so we don't make redundant copies
+        _scope = NULL;
+    }
+
+    if (!parent)
+    {
+        assert(sc->parent);
+        parent = sc->parent;
+    }
+
+    if (this->errors)
+        type = Type::terror;
+    type = type->semantic(loc, sc);
+
+    if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
+    {
+        TemplateInstance *ti = ((TypeClass *)type)->sym->isInstantiated();
+        if (ti && isError(ti))
+            ((TypeClass *)type)->sym = this;
+    }
+
+    // Ungag errors when not speculative
+    Ungag ungag = ungagSpeculative();
+
+    if (semanticRun == PASSinit)
+    {
+        protection = sc->protection;
+
+        storage_class |= sc->stc;
+        if (storage_class & STCdeprecated)
+            isdeprecated = true;
+        if (storage_class & STCauto)
+            error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?");
+        if (storage_class & STCscope)
+            isscope = true;
+        if (storage_class & STCabstract)
+            isabstract = ABSyes;
+
+        userAttribDecl = sc->userAttribDecl;
+
+        if (sc->linkage == LINKcpp)
+            cpp = true;
+        if (sc->linkage == LINKobjc)
+            objc()->setObjc(this);
+    }
+    else if (symtab && !scx)
+    {
+        semanticRun = PASSsemanticdone;
+        return;
+    }
+    semanticRun = PASSsemantic;
+
+    if (baseok < BASEOKdone)
+    {
+        baseok = BASEOKin;
+
+        // Expand any tuples in baseclasses[]
+        for (size_t i = 0; i < baseclasses->dim; )
+        {
+            BaseClass *b = (*baseclasses)[i];
+            b->type = resolveBase(this, sc, scx, b->type);
+
+            Type *tb = b->type->toBasetype();
+            if (tb->ty == Ttuple)
+            {
+                TypeTuple *tup = (TypeTuple *)tb;
+                baseclasses->remove(i);
+                size_t dim = Parameter::dim(tup->arguments);
+                for (size_t j = 0; j < dim; j++)
+                {
+                    Parameter *arg = Parameter::getNth(tup->arguments, j);
+                    b = new BaseClass(arg->type);
+                    baseclasses->insert(i + j, b);
+                }
+            }
+            else
+                i++;
+        }
+
+        if (baseok >= BASEOKdone)
+        {
+            //printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun);
+            if (semanticRun >= PASSsemanticdone)
+                return;
+            goto Lancestorsdone;
+        }
+
+        // See if there's a base class as first in baseclasses[]
+        if (baseclasses->dim)
+        {
+            BaseClass *b = (*baseclasses)[0];
+            Type *tb = b->type->toBasetype();
+            TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
+            if (!tc)
+            {
+                if (b->type != Type::terror)
+                    error("base type must be class or interface, not %s", b->type->toChars());
+                baseclasses->remove(0);
+                goto L7;
+            }
+
+            if (tc->sym->isDeprecated())
+            {
+                if (!isDeprecated())
+                {
+                    // Deriving from deprecated class makes this one deprecated too
+                    isdeprecated = true;
+
+                    tc->checkDeprecated(loc, sc);
+                }
+            }
+
+            if (tc->sym->isInterfaceDeclaration())
+                goto L7;
+
+            for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass)
+            {
+                if (cdb == this)
+                {
+                    error("circular inheritance");
+                    baseclasses->remove(0);
+                    goto L7;
+                }
+            }
+
+            /* Bugzilla 11034: Essentially, class inheritance hierarchy
+             * and instance size of each classes are orthogonal information.
+             * Therefore, even if tc->sym->sizeof == SIZEOKnone,
+             * we need to set baseClass field for class covariance check.
+             */
+            baseClass = tc->sym;
+            b->sym = baseClass;
+
+            if (tc->sym->_scope && tc->sym->baseok < BASEOKdone)
+                resolveBase(this, sc, scx, tc->sym); // Try to resolve forward reference
+            if (tc->sym->baseok < BASEOKdone)
+            {
+                //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
+                if (tc->sym->_scope)
+                    tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+                baseok = BASEOKnone;
+            }
+         L7: ;
+        }
+
+        // Treat the remaining entries in baseclasses as interfaces
+        // Check for errors, handle forward references
+        for (size_t i = (baseClass ? 1 : 0); i < baseclasses->dim; )
+        {
+            BaseClass *b = (*baseclasses)[i];
+            Type *tb = b->type->toBasetype();
+            TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
+            if (!tc || !tc->sym->isInterfaceDeclaration())
+            {
+                if (b->type != Type::terror)
+                    error("base type must be interface, not %s", b->type->toChars());
+                baseclasses->remove(i);
+                continue;
+            }
+
+            // Check for duplicate interfaces
+            for (size_t j = (baseClass ? 1 : 0); j < i; j++)
+            {
+                BaseClass *b2 = (*baseclasses)[j];
+                if (b2->sym == tc->sym)
+                {
+                    error("inherits from duplicate interface %s", b2->sym->toChars());
+                    baseclasses->remove(i);
+                    continue;
+                }
+            }
+
+            if (tc->sym->isDeprecated())
+            {
+                if (!isDeprecated())
+                {
+                    // Deriving from deprecated class makes this one deprecated too
+                    isdeprecated = true;
+
+                    tc->checkDeprecated(loc, sc);
+                }
+            }
+
+            b->sym = tc->sym;
+
+            if (tc->sym->_scope && tc->sym->baseok < BASEOKdone)
+                resolveBase(this, sc, scx, tc->sym); // Try to resolve forward reference
+            if (tc->sym->baseok < BASEOKdone)
+            {
+                //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
+                if (tc->sym->_scope)
+                    tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+                baseok = BASEOKnone;
+            }
+            i++;
+        }
+        if (baseok == BASEOKnone)
+        {
+            // Forward referencee of one or more bases, try again later
+            _scope = scx ? scx : sc->copy();
+            _scope->setNoFree();
+            _scope->_module->addDeferredSemantic(this);
+            //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars());
+            return;
+        }
+        baseok = BASEOKdone;
+
+        // If no base class, and this is not an Object, use Object as base class
+        if (!baseClass && ident != Id::Object && !cpp)
+        {
+            if (!object || object->errors)
+                badObjectDotD(this);
+
+            Type *t = object->type;
+            t = t->semantic(loc, sc)->toBasetype();
+            if (t->ty == Terror)
+                badObjectDotD(this);
+            assert(t->ty == Tclass);
+            TypeClass *tc = (TypeClass *)t;
+
+            BaseClass *b = new BaseClass(tc);
+            baseclasses->shift(b);
+
+            baseClass = tc->sym;
+            assert(!baseClass->isInterfaceDeclaration());
+            b->sym = baseClass;
+        }
+        if (baseClass)
+        {
+            if (baseClass->storage_class & STCfinal)
+                error("cannot inherit from final class %s", baseClass->toChars());
+
+            // Inherit properties from base class
+            if (baseClass->isCOMclass())
+                com = true;
+            if (baseClass->isCPPclass())
+                cpp = true;
+            if (baseClass->isscope)
+                isscope = true;
+            enclosing = baseClass->enclosing;
+            storage_class |= baseClass->storage_class & STC_TYPECTOR;
+        }
+
+        interfaces.length = baseclasses->dim - (baseClass ? 1 : 0);
+        interfaces.ptr = baseclasses->tdata() + (baseClass ? 1 : 0);
+
+        for (size_t i = 0; i < interfaces.length; i++)
+        {
+            BaseClass *b = interfaces.ptr[i];
+            // If this is an interface, and it derives from a COM interface,
+            // then this is a COM interface too.
+            if (b->sym->isCOMinterface())
+                com = true;
+            if (cpp && !b->sym->isCPPinterface())
+            {
+                ::error(loc, "C++ class '%s' cannot implement D interface '%s'", toPrettyChars(), b->sym->toPrettyChars());
+            }
+        }
+
+        interfaceSemantic(sc);
+    }
+Lancestorsdone:
+    //printf("\tClassDeclaration::semantic(%s) baseok = %d\n", toChars(), baseok);
+
+    if (!members)               // if opaque declaration
+    {
+        semanticRun = PASSsemanticdone;
+        return;
+    }
+    if (!symtab)
+    {
+        symtab = new DsymbolTable();
+
+        /* Bugzilla 12152: The semantic analysis of base classes should be finished
+         * before the members semantic analysis of this class, in order to determine
+         * vtbl in this class. However if a base class refers the member of this class,
+         * it can be resolved as a normal forward reference.
+         * Call addMember() and setScope() to make this class members visible from the base classes.
+         */
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            s->addMember(sc, this);
+        }
+
+        Scope *sc2 = newScope(sc);
+
+        /* Set scope so if there are forward references, we still might be able to
+         * resolve individual members like enums.
+         */
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            //printf("[%d] setScope %s %s, sc2 = %p\n", i, s->kind(), s->toChars(), sc2);
+            s->setScope(sc2);
+        }
+
+        sc2->pop();
+    }
+
+    for (size_t i = 0; i < baseclasses->dim; i++)
+    {
+        BaseClass *b = (*baseclasses)[i];
+        Type *tb = b->type->toBasetype();
+        assert(tb->ty == Tclass);
+        TypeClass *tc = (TypeClass *)tb;
+
+        if (tc->sym->semanticRun < PASSsemanticdone)
+        {
+            // Forward referencee of one or more bases, try again later
+            _scope = scx ? scx : sc->copy();
+            _scope->setNoFree();
+            if (tc->sym->_scope)
+                tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+            _scope->_module->addDeferredSemantic(this);
+            //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars());
+            return;
+        }
+    }
+
+    if (baseok == BASEOKdone)
+    {
+        baseok = BASEOKsemanticdone;
+
+        // initialize vtbl
+        if (baseClass)
+        {
+            if (cpp && baseClass->vtbl.dim == 0)
+            {
+                error("C++ base class %s needs at least one virtual function", baseClass->toChars());
+            }
+
+            // Copy vtbl[] from base class
+            vtbl.setDim(baseClass->vtbl.dim);
+            memcpy(vtbl.tdata(), baseClass->vtbl.tdata(), sizeof(void *) * vtbl.dim);
+
+            vthis = baseClass->vthis;
+        }
+        else
+        {
+            // No base class, so this is the root of the class hierarchy
+            vtbl.setDim(0);
+            if (vtblOffset())
+                vtbl.push(this);            // leave room for classinfo as first member
+        }
+
+        /* If this is a nested class, add the hidden 'this'
+         * member which is a pointer to the enclosing scope.
+         */
+        if (vthis)              // if inheriting from nested class
+        {
+            // Use the base class's 'this' member
+            if (storage_class & STCstatic)
+                error("static class cannot inherit from nested class %s", baseClass->toChars());
+            if (toParent2() != baseClass->toParent2() &&
+                (!toParent2() ||
+                 !baseClass->toParent2()->getType() ||
+                 !baseClass->toParent2()->getType()->isBaseOf(toParent2()->getType(), NULL)))
+            {
+                if (toParent2())
+                {
+                    error("is nested within %s, but super class %s is nested within %s",
+                        toParent2()->toChars(),
+                        baseClass->toChars(),
+                        baseClass->toParent2()->toChars());
+                }
+                else
+                {
+                    error("is not nested, but super class %s is nested within %s",
+                        baseClass->toChars(),
+                        baseClass->toParent2()->toChars());
+                }
+                enclosing = NULL;
+            }
+        }
+        else
+            makeNested();
+    }
+
+    Scope *sc2 = newScope(sc);
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->importAll(sc2);
+    }
+
+    // Note that members.dim can grow due to tuple expansion during semantic()
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->semantic(sc2);
+    }
+
+    if (!determineFields())
+    {
+        assert(type == Type::terror);
+        sc2->pop();
+        return;
+    }
+
+    /* Following special member functions creation needs semantic analysis
+     * completion of sub-structs in each field types.
+     */
+    for (size_t i = 0; i < fields.dim; i++)
+    {
+        VarDeclaration *v = fields[i];
+        Type *tb = v->type->baseElemOf();
+        if (tb->ty != Tstruct)
+            continue;
+        StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+        if (sd->semanticRun >= PASSsemanticdone)
+            continue;
+
+        sc2->pop();
+
+        _scope = scx ? scx : sc->copy();
+        _scope->setNoFree();
+        _scope->_module->addDeferredSemantic(this);
+        //printf("\tdeferring %s\n", toChars());
+        return;
+    }
+
+    /* Look for special member functions.
+     * They must be in this class, not in a base class.
+     */
+
+    // Can be in base class
+    aggNew    =    (NewDeclaration *)search(Loc(), Id::classNew);
+    aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete);
+
+    // Look for the constructor
+    ctor = searchCtor();
+
+    if (!ctor && noDefaultCtor)
+    {
+        // A class object is always created by constructor, so this check is legitimate.
+        for (size_t i = 0; i < fields.dim; i++)
+        {
+            VarDeclaration *v = fields[i];
+            if (v->storage_class & STCnodefaultctor)
+                ::error(v->loc, "field %s must be initialized in constructor", v->toChars());
+        }
+    }
+
+    // If this class has no constructor, but base class has a default
+    // ctor, create a constructor:
+    //    this() { }
+    if (!ctor && baseClass && baseClass->ctor)
+    {
+        FuncDeclaration *fd = resolveFuncCall(loc, sc2, baseClass->ctor, NULL, NULL, NULL, 1);
+        if (fd && !fd->errors)
+        {
+            //printf("Creating default this(){} for class %s\n", toChars());
+            TypeFunction *btf = (TypeFunction *)fd->type;
+            TypeFunction *tf = new TypeFunction(NULL, NULL, 0, LINKd, fd->storage_class);
+            tf->purity = btf->purity;
+            tf->isnothrow = btf->isnothrow;
+            tf->isnogc = btf->isnogc;
+            tf->trust = btf->trust;
+
+            CtorDeclaration *ctor = new CtorDeclaration(loc, Loc(), 0, tf);
+            ctor->fbody = new CompoundStatement(Loc(), new Statements());
+
+            members->push(ctor);
+            ctor->addMember(sc, this);
+            ctor->semantic(sc2);
+
+            this->ctor = ctor;
+            defaultCtor = ctor;
+        }
+        else
+        {
+            error("cannot implicitly generate a default ctor when base class %s is missing a default ctor", baseClass->toPrettyChars());
+        }
+    }
+
+    dtor = buildDtor(this, sc2);
+
+    if (FuncDeclaration *f = hasIdentityOpAssign(this, sc2))
+    {
+        if (!(f->storage_class & STCdisable))
+            error(f->loc, "identity assignment operator overload is illegal");
+    }
+
+    inv = buildInv(this, sc2);
+
+    Module::dprogress++;
+    semanticRun = PASSsemanticdone;
+    //printf("-ClassDeclaration.semantic(%s), type = %p\n", toChars(), type);
+    //members.print();
+
+    sc2->pop();
+
+    if (type->ty != Tclass || ((TypeClass *)type)->sym != this)
+    {
+        // https://issues.dlang.org/show_bug.cgi?id=17492
+        ClassDeclaration *cd = ((TypeClass *)type)->sym;
+#if 0
+        printf("this = %p %s\n", this, this->toPrettyChars());
+        printf("type = %d sym = %p, %s\n", type->ty, cd, cd->toPrettyChars());
+#endif
+        error("already exists at %s. Perhaps in another function with the same name?", cd->loc.toChars());
+    }
+
+    if (global.errors != errors)
+    {
+        // The type is no good.
+        type = Type::terror;
+        this->errors = true;
+        if (deferred)
+            deferred->errors = true;
+    }
+
+    // Verify fields of a synchronized class are not public
+    if (storage_class & STCsynchronized)
+    {
+        for (size_t i = 0; i < fields.dim; i++)
+        {
+            VarDeclaration *vd = fields[i];
+            if (!vd->isThisDeclaration() &&
+                !vd->prot().isMoreRestrictiveThan(Prot(PROTpublic)))
+            {
+                vd->error("Field members of a synchronized class cannot be %s",
+                    protectionToChars(vd->prot().kind));
+            }
+        }
+    }
+
+    if (deferred && !global.gag)
+    {
+        deferred->semantic2(sc);
+        deferred->semantic3(sc);
+    }
+    //printf("-ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
+}
+
+/*********************************************
+ * Determine if 'this' is a base class of cd.
+ * This is used to detect circular inheritance only.
+ */
+
+bool ClassDeclaration::isBaseOf2(ClassDeclaration *cd)
+{
+    if (!cd)
+        return false;
+    //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
+    for (size_t i = 0; i < cd->baseclasses->dim; i++)
+    {
+        BaseClass *b = (*cd->baseclasses)[i];
+        if (b->sym == this || isBaseOf2(b->sym))
+            return true;
+    }
+    return false;
+}
+
+/*******************************************
+ * Determine if 'this' is a base class of cd.
+ */
+
+bool ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
+{
+    //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
+    if (poffset)
+        *poffset = 0;
+    while (cd)
+    {
+        /* cd->baseClass might not be set if cd is forward referenced.
+         */
+        if (!cd->baseClass && cd->_scope && !cd->isInterfaceDeclaration())
+        {
+            cd->semantic(NULL);
+            if (!cd->baseClass && cd->_scope)
+                cd->error("base class is forward referenced by %s", toChars());
+        }
+
+        if (this == cd->baseClass)
+            return true;
+
+        cd = cd->baseClass;
+    }
+    return false;
+}
+
+/*********************************************
+ * Determine if 'this' has complete base class information.
+ * This is used to detect forward references in covariant overloads.
+ */
+
+bool ClassDeclaration::isBaseInfoComplete()
+{
+    return baseok >= BASEOKdone;
+}
+
+Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("%s.ClassDeclaration::search('%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
+
+    //if (_scope) printf("%s baseok = %d\n", toChars(), baseok);
+    if (_scope && baseok < BASEOKdone)
+    {
+        if (!inuse)
+        {
+            // must semantic on base class/interfaces
+            ++inuse;
+            semantic(NULL);
+            --inuse;
+        }
+    }
+
+    if (!members || !symtab)    // opaque or addMember is not yet done
+    {
+        error("is forward referenced when looking for '%s'", ident->toChars());
+        //*(char*)0=0;
+        return NULL;
+    }
+
+    Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
+
+    // don't search imports of base classes
+    if (flags & SearchImportsOnly)
+        return s;
+
+    if (!s)
+    {
+        // Search bases classes in depth-first, left to right order
+
+        for (size_t i = 0; i < baseclasses->dim; i++)
+        {
+            BaseClass *b = (*baseclasses)[i];
+
+            if (b->sym)
+            {
+                if (!b->sym->symtab)
+                    error("base %s is forward referenced", b->sym->ident->toChars());
+                else
+                {
+                    s = b->sym->search(loc, ident, flags);
+                    if (!s)
+                        continue;
+                    else if (s == this) // happens if s is nested in this and derives from this
+                        s = NULL;
+                    else if (!(flags & IgnoreSymbolVisibility) && !(s->prot().kind == PROTprotected) && !symbolIsVisible(this, s))
+                        s = NULL;
+                    else
+                        break;
+                }
+            }
+        }
+    }
+    return s;
+}
+
+/************************************
+ * Search base classes in depth-first, left-to-right order for
+ * a class or interface named 'ident'.
+ * Stops at first found. Does not look for additional matches.
+ * Params:
+ *  ident = identifier to search for
+ * Returns:
+ *  ClassDeclaration if found, null if not
+ */
+ClassDeclaration *ClassDeclaration::searchBase(Identifier *ident)
+{
+    for (size_t i = 0; i < baseclasses->dim; i++)
+    {
+        BaseClass *b = (*baseclasses)[i];
+        ClassDeclaration *cdb = b->type->isClassHandle();
+        if (!cdb)   // Bugzilla 10616
+            return NULL;
+        if (cdb->ident->equals(ident))
+            return cdb;
+        cdb = cdb->searchBase(ident);
+        if (cdb)
+            return cdb;
+    }
+    return NULL;
+}
+
+/****
+ * Runs through the inheritance graph to set the BaseClass.offset fields.
+ * Recursive in order to account for the size of the interface classes, if they are
+ * more than just interfaces.
+ * Params:
+ *      cd = interface to look at
+ *      baseOffset = offset of where cd will be placed
+ * Returns:
+ *      subset of instantiated size used by cd for interfaces
+ */
+static unsigned membersPlace(BaseClasses *vtblInterfaces, size_t &bi, ClassDeclaration *cd, unsigned baseOffset)
+{
+    //printf("    membersPlace(%s, %d)\n", cd->toChars(), baseOffset);
+    unsigned offset = baseOffset;
+
+    for (size_t i = 0; i < cd->interfaces.length; i++)
+    {
+        BaseClass *b = cd->interfaces.ptr[i];
+        if (b->sym->sizeok != SIZEOKdone)
+            b->sym->finalizeSize();
+        assert(b->sym->sizeok == SIZEOKdone);
+
+        if (!b->sym->alignsize)
+            b->sym->alignsize = Target::ptrsize;
+        cd->alignmember(b->sym->alignsize, b->sym->alignsize, &offset);
+        assert(bi < vtblInterfaces->dim);
+        BaseClass *bv = (*vtblInterfaces)[bi];
+        if (b->sym->interfaces.length == 0)
+        {
+            //printf("\tvtblInterfaces[%d] b=%p b->sym = %s, offset = %d\n", bi, bv, bv->sym->toChars(), offset);
+            bv->offset = offset;
+            ++bi;
+            // All the base interfaces down the left side share the same offset
+            for (BaseClass *b2 = bv; b2->baseInterfaces.length; )
+            {
+                b2 = &b2->baseInterfaces.ptr[0];
+                b2->offset = offset;
+                //printf("\tvtblInterfaces[%d] b=%p   sym = %s, offset = %d\n", bi, b2, b2->sym->toChars(), b2->offset);
+            }
+        }
+        membersPlace(vtblInterfaces, bi, b->sym, offset);
+        //printf(" %s size = %d\n", b->sym->toChars(), b->sym->structsize);
+        offset += b->sym->structsize;
+        if (cd->alignsize < b->sym->alignsize)
+            cd->alignsize = b->sym->alignsize;
+    }
+    return offset - baseOffset;
+}
+
+void ClassDeclaration::finalizeSize()
+{
+    assert(sizeok != SIZEOKdone);
+
+    // Set the offsets of the fields and determine the size of the class
+    if (baseClass)
+    {
+        assert(baseClass->sizeok == SIZEOKdone);
+
+        alignsize = baseClass->alignsize;
+        structsize = baseClass->structsize;
+        if (cpp && global.params.isWindows)
+            structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
+    }
+    else if (isInterfaceDeclaration())
+    {
+        if (interfaces.length == 0)
+        {
+            alignsize = Target::ptrsize;
+            structsize = Target::ptrsize;      // allow room for __vptr
+        }
+    }
+    else
+    {
+        alignsize = Target::ptrsize;
+        structsize = Target::ptrsize;      // allow room for __vptr
+        if (!cpp)
+            structsize += Target::ptrsize; // allow room for __monitor
+    }
+
+    //printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
+    size_t bi = 0;                  // index into vtblInterfaces[]
+
+    // Add vptr's for any interfaces implemented by this class
+    structsize += membersPlace(vtblInterfaces, bi, this, structsize);
+
+    if (isInterfaceDeclaration())
+    {
+        sizeok = SIZEOKdone;
+        return;
+    }
+
+    // FIXME: Currently setFieldOffset functions need to increase fields
+    // to calculate each variable offsets. It can be improved later.
+    fields.setDim(0);
+
+    unsigned offset = structsize;
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->setFieldOffset(this, &offset, false);
+    }
+
+    sizeok = SIZEOKdone;
+
+    // Calculate fields[i]->overlapped
+    checkOverlappedFields();
+}
+
+/**********************************************************
+ * fd is in the vtbl[] for this class.
+ * Return 1 if function is hidden (not findable through search).
+ */
+
+int isf(void *param, Dsymbol *s)
+{
+    FuncDeclaration *fd = s->isFuncDeclaration();
+    if (!fd)
+        return 0;
+    //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars());
+    return (RootObject *)param == fd;
+}
+
+bool ClassDeclaration::isFuncHidden(FuncDeclaration *fd)
+{
+    //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars());
+    Dsymbol *s = search(Loc(), fd->ident, IgnoreAmbiguous | IgnoreErrors);
+    if (!s)
+    {
+        //printf("not found\n");
+        /* Because, due to a hack, if there are multiple definitions
+         * of fd->ident, NULL is returned.
+         */
+        return false;
+    }
+    s = s->toAlias();
+    OverloadSet *os = s->isOverloadSet();
+    if (os)
+    {
+        for (size_t i = 0; i < os->a.dim; i++)
+        {
+            Dsymbol *s2 = os->a[i];
+            FuncDeclaration *f2 = s2->isFuncDeclaration();
+            if (f2 && overloadApply(f2, (void *)fd, &isf))
+                return false;
+        }
+        return true;
+    }
+    else
+    {
+        FuncDeclaration *fdstart = s->isFuncDeclaration();
+        //printf("%s fdstart = %p\n", s->kind(), fdstart);
+        if (overloadApply(fdstart, (void *)fd, &isf))
+            return false;
+
+        return !fd->parent->isTemplateMixin();
+    }
+}
+
+/****************
+ * Find virtual function matching identifier and type.
+ * Used to build virtual function tables for interface implementations.
+ */
+
+FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf)
+{
+    //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars());
+    FuncDeclaration *fdmatch = NULL;
+    FuncDeclaration *fdambig = NULL;
+
+    ClassDeclaration *cd = this;
+    Dsymbols *vtbl = &cd->vtbl;
+    while (1)
+    {
+        for (size_t i = 0; i < vtbl->dim; i++)
+        {
+            FuncDeclaration *fd = (*vtbl)[i]->isFuncDeclaration();
+            if (!fd)
+                continue;               // the first entry might be a ClassInfo
+
+            //printf("\t[%d] = %s\n", i, fd->toChars());
+            if (ident == fd->ident &&
+                fd->type->covariant(tf) == 1)
+            {
+                //printf("fd->parent->isClassDeclaration() = %p\n", fd->parent->isClassDeclaration());
+                if (!fdmatch)
+                    goto Lfd;
+                if (fd == fdmatch)
+                    goto Lfdmatch;
+
+                {
+                // Function type matcing: exact > covariant
+                MATCH m1 = tf->equals(fd     ->type) ? MATCHexact : MATCHnomatch;
+                MATCH m2 = tf->equals(fdmatch->type) ? MATCHexact : MATCHnomatch;
+                if (m1 > m2)
+                    goto Lfd;
+                else if (m1 < m2)
+                    goto Lfdmatch;
+                }
+
+                {
+                MATCH m1 = (tf->mod == fd     ->type->mod) ? MATCHexact : MATCHnomatch;
+                MATCH m2 = (tf->mod == fdmatch->type->mod) ? MATCHexact : MATCHnomatch;
+                if (m1 > m2)
+                    goto Lfd;
+                else if (m1 < m2)
+                    goto Lfdmatch;
+                }
+
+                {
+                // The way of definition: non-mixin > mixin
+                MATCH m1 = fd     ->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch;
+                MATCH m2 = fdmatch->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch;
+                if (m1 > m2)
+                    goto Lfd;
+                else if (m1 < m2)
+                    goto Lfdmatch;
+                }
+
+                fdambig = fd;
+                //printf("Lambig fdambig = %s %s [%s]\n", fdambig->toChars(), fdambig->type->toChars(), fdambig->loc.toChars());
+                continue;
+
+            Lfd:
+                fdmatch = fd, fdambig = NULL;
+                //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch->toChars(), fdmatch->type->toChars(), fdmatch->loc.toChars());
+                continue;
+
+            Lfdmatch:
+                continue;
+            }
+            //else printf("\t\t%d\n", fd->type->covariant(tf));
+        }
+        if (!cd)
+            break;
+        vtbl = &cd->vtblFinal;
+        cd = cd->baseClass;
+    }
+
+    if (fdambig)
+        error("ambiguous virtual function %s", fdambig->toChars());
+    return fdmatch;
+}
+
+void ClassDeclaration::interfaceSemantic(Scope *sc)
+{
+    vtblInterfaces = new BaseClasses();
+    vtblInterfaces->reserve(interfaces.length);
+
+    for (size_t i = 0; i < interfaces.length; i++)
+    {
+        BaseClass *b = interfaces.ptr[i];
+        vtblInterfaces->push(b);
+        b->copyBaseInterfaces(vtblInterfaces);
+    }
+}
+
+/****************************************
+ */
+
+bool ClassDeclaration::isCOMclass() const
+{
+    return com;
+}
+
+bool ClassDeclaration::isCOMinterface() const
+{
+    return false;
+}
+
+bool ClassDeclaration::isCPPclass() const
+{
+    return cpp;
+}
+
+bool ClassDeclaration::isCPPinterface() const
+{
+    return false;
+}
+
+
+/****************************************
+ */
+
+bool ClassDeclaration::isAbstract()
+{
+    if (isabstract != ABSfwdref)
+        return isabstract == ABSyes;
+
+    /* Bugzilla 11169: Resolve forward references to all class member functions,
+     * and determine whether this class is abstract.
+     */
+    struct SearchAbstract
+    {
+        static int fp(Dsymbol *s, void* param)
+        {
+            FuncDeclaration *fd = s->isFuncDeclaration();
+            if (!fd)
+                return 0;
+            if (fd->storage_class & STCstatic)
+                return 0;
+
+            if (fd->_scope)
+                fd->semantic(NULL);
+
+            if (fd->isAbstract())
+                return 1;
+            return 0;
+        }
+    };
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        if (s->apply(&SearchAbstract::fp, this))
+        {
+            isabstract = ABSyes;
+            return true;
+        }
+    }
+
+    /* Iterate inherited member functions and check their abstract attribute.
+     */
+    for (size_t i = 1; i < vtbl.dim; i++)
+    {
+        FuncDeclaration *fd = vtbl[i]->isFuncDeclaration();
+        //if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd->loc.toChars(), fd->toChars());
+        if (!fd || fd->isAbstract())
+        {
+            isabstract = ABSyes;
+            return true;
+        }
+    }
+
+    isabstract = ABSno;
+    return false;
+}
+
+
+/****************************************
+ * Determine if slot 0 of the vtbl[] is reserved for something else.
+ * For class objects, yes, this is where the classinfo ptr goes.
+ * For COM interfaces, no.
+ * For non-COM interfaces, yes, this is where the Interface ptr goes.
+ * Returns:
+ *      0       vtbl[0] is first virtual function pointer
+ *      1       vtbl[0] is classinfo/interfaceinfo pointer
+ */
+
+int ClassDeclaration::vtblOffset() const
+{
+    return cpp ? 0 : 1;
+}
+
+/****************************************
+ */
+
+const char *ClassDeclaration::kind()
+{
+    return "class";
+}
+
+/****************************************
+ */
+
+void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses)
+{
+    aclasses->push(this);
+}
+
+/********************************* InterfaceDeclaration ****************************/
+
+InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
+    : ClassDeclaration(loc, id, baseclasses, NULL, false)
+{
+    if (id == Id::IUnknown)     // IUnknown is the root of all COM interfaces
+    {
+        com = true;
+        cpp = true;             // IUnknown is also a C++ interface
+    }
+}
+
+Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s)
+{
+    InterfaceDeclaration *id =
+        s ? (InterfaceDeclaration *)s
+          : new InterfaceDeclaration(loc, ident, NULL);
+    return ClassDeclaration::syntaxCopy(id);
+}
+
+Scope *InterfaceDeclaration::newScope(Scope *sc)
+{
+    Scope *sc2 = ClassDeclaration::newScope(sc);
+    if (com)
+        sc2->linkage = LINKwindows;
+    else if (cpp)
+        sc2->linkage = LINKcpp;
+    else if (isobjc)
+        sc2->linkage = LINKobjc;
+    return sc2;
+}
+
+void InterfaceDeclaration::semantic(Scope *sc)
+{
+    //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    int errors = global.errors;
+
+    //printf("+InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type);
+
+    Scope *scx = NULL;
+    if (_scope)
+    {
+        sc = _scope;
+        scx = _scope;            // save so we don't make redundant copies
+        _scope = NULL;
+    }
+
+    if (!parent)
+    {
+        assert(sc->parent && sc->func);
+        parent = sc->parent;
+    }
+    assert(parent && !isAnonymous());
+
+    if (this->errors)
+        type = Type::terror;
+    type = type->semantic(loc, sc);
+
+    if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
+    {
+        TemplateInstance *ti = ((TypeClass *)type)->sym->isInstantiated();
+        if (ti && isError(ti))
+            ((TypeClass *)type)->sym = this;
+    }
+
+    // Ungag errors when not speculative
+    Ungag ungag = ungagSpeculative();
+
+    if (semanticRun == PASSinit)
+    {
+        protection = sc->protection;
+
+        storage_class |= sc->stc;
+        if (storage_class & STCdeprecated)
+            isdeprecated = true;
+
+        userAttribDecl = sc->userAttribDecl;
+    }
+    else if (symtab)
+    {
+        if (sizeok == SIZEOKdone || !scx)
+        {
+            semanticRun = PASSsemanticdone;
+            return;
+        }
+    }
+    semanticRun = PASSsemantic;
+
+    if (baseok < BASEOKdone)
+    {
+        baseok = BASEOKin;
+
+        // Expand any tuples in baseclasses[]
+        for (size_t i = 0; i < baseclasses->dim; )
+        {
+            BaseClass *b = (*baseclasses)[i];
+            b->type = resolveBase(this, sc, scx, b->type);
+
+            Type *tb = b->type->toBasetype();
+            if (tb->ty == Ttuple)
+            {
+                TypeTuple *tup = (TypeTuple *)tb;
+                baseclasses->remove(i);
+                size_t dim = Parameter::dim(tup->arguments);
+                for (size_t j = 0; j < dim; j++)
+                {
+                    Parameter *arg = Parameter::getNth(tup->arguments, j);
+                    b = new BaseClass(arg->type);
+                    baseclasses->insert(i + j, b);
+                }
+            }
+            else
+                i++;
+        }
+
+        if (baseok >= BASEOKdone)
+        {
+            //printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun);
+            if (semanticRun >= PASSsemanticdone)
+                return;
+            goto Lancestorsdone;
+        }
+
+        if (!baseclasses->dim && sc->linkage == LINKcpp)
+            cpp = true;
+        if (sc->linkage == LINKobjc)
+            objc()->setObjc(this);
+
+        // Check for errors, handle forward references
+        for (size_t i = 0; i < baseclasses->dim; )
+        {
+            BaseClass *b = (*baseclasses)[i];
+            Type *tb = b->type->toBasetype();
+            TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
+            if (!tc || !tc->sym->isInterfaceDeclaration())
+            {
+                if (b->type != Type::terror)
+                    error("base type must be interface, not %s", b->type->toChars());
+                baseclasses->remove(i);
+                continue;
+            }
+
+            // Check for duplicate interfaces
+            for (size_t j = 0; j < i; j++)
+            {
+                BaseClass *b2 = (*baseclasses)[j];
+                if (b2->sym == tc->sym)
+                {
+                    error("inherits from duplicate interface %s", b2->sym->toChars());
+                    baseclasses->remove(i);
+                    continue;
+                }
+            }
+
+            if (tc->sym == this || isBaseOf2(tc->sym))
+            {
+                error("circular inheritance of interface");
+                baseclasses->remove(i);
+                continue;
+            }
+
+            if (tc->sym->isDeprecated())
+            {
+                if (!isDeprecated())
+                {
+                    // Deriving from deprecated class makes this one deprecated too
+                    isdeprecated = true;
+
+                    tc->checkDeprecated(loc, sc);
+                }
+            }
+
+            b->sym = tc->sym;
+
+            if (tc->sym->_scope && tc->sym->baseok < BASEOKdone)
+                resolveBase(this, sc, scx, tc->sym); // Try to resolve forward reference
+            if (tc->sym->baseok < BASEOKdone)
+            {
+                //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
+                if (tc->sym->_scope)
+                    tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+                baseok = BASEOKnone;
+            }
+            i++;
+        }
+        if (baseok == BASEOKnone)
+        {
+            // Forward referencee of one or more bases, try again later
+            _scope = scx ? scx : sc->copy();
+            _scope->setNoFree();
+            _scope->_module->addDeferredSemantic(this);
+            return;
+        }
+        baseok = BASEOKdone;
+
+        interfaces.length = baseclasses->dim;
+        interfaces.ptr = baseclasses->tdata();
+
+        for (size_t i = 0; i < interfaces.length; i++)
+        {
+            BaseClass *b = interfaces.ptr[i];
+            // If this is an interface, and it derives from a COM interface,
+            // then this is a COM interface too.
+            if (b->sym->isCOMinterface())
+                com = true;
+            if (b->sym->isCPPinterface())
+                cpp = true;
+        }
+
+        interfaceSemantic(sc);
+    }
+Lancestorsdone:
+
+    if (!members)               // if opaque declaration
+    {
+        semanticRun = PASSsemanticdone;
+        return;
+    }
+    if (!symtab)
+        symtab = new DsymbolTable();
+
+    for (size_t i = 0; i < baseclasses->dim; i++)
+    {
+        BaseClass *b = (*baseclasses)[i];
+        Type *tb = b->type->toBasetype();
+        assert(tb->ty == Tclass);
+        TypeClass *tc = (TypeClass *)tb;
+
+        if (tc->sym->semanticRun < PASSsemanticdone)
+        {
+            // Forward referencee of one or more bases, try again later
+            _scope = scx ? scx : sc->copy();
+            _scope->setNoFree();
+            if (tc->sym->_scope)
+                tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+            _scope->_module->addDeferredSemantic(this);
+            return;
+        }
+    }
+
+    if (baseok == BASEOKdone)
+    {
+        baseok = BASEOKsemanticdone;
+
+        // initialize vtbl
+        if (vtblOffset())
+            vtbl.push(this);                // leave room at vtbl[0] for classinfo
+
+        // Cat together the vtbl[]'s from base interfaces
+        for (size_t i = 0; i < interfaces.length; i++)
+        {
+            BaseClass *b = interfaces.ptr[i];
+
+            // Skip if b has already appeared
+            for (size_t k = 0; k < i; k++)
+            {
+                if (b == interfaces.ptr[k])
+                    goto Lcontinue;
+            }
+
+            // Copy vtbl[] from base class
+            if (b->sym->vtblOffset())
+            {
+                size_t d = b->sym->vtbl.dim;
+                if (d > 1)
+                {
+                    vtbl.reserve(d - 1);
+                    for (size_t j = 1; j < d; j++)
+                        vtbl.push(b->sym->vtbl[j]);
+                }
+            }
+            else
+            {
+                vtbl.append(&b->sym->vtbl);
+            }
+
+          Lcontinue:
+            ;
+        }
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->addMember(sc, this);
+    }
+
+    Scope *sc2 = newScope(sc);
+
+    /* Set scope so if there are forward references, we still might be able to
+     * resolve individual members like enums.
+     */
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        //printf("setScope %s %s\n", s->kind(), s->toChars());
+        s->setScope(sc2);
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->importAll(sc2);
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->semantic(sc2);
+    }
+
+    Module::dprogress++;
+    semanticRun = PASSsemanticdone;
+    //printf("-InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type);
+    //members->print();
+
+    sc2->pop();
+
+    if (global.errors != errors)
+    {
+        // The type is no good.
+        type = Type::terror;
+    }
+
+#if 0
+    if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
+    {
+        printf("this = %p %s\n", this, this->toChars());
+        printf("type = %d sym = %p\n", type->ty, ((TypeClass *)type)->sym);
+      }
+#endif
+    assert(type->ty != Tclass || ((TypeClass *)type)->sym == this);
+}
+
+/*******************************************
+ * Determine if 'this' is a base class of cd.
+ * (Actually, if it is an interface supported by cd)
+ * Output:
+ *      *poffset        offset to start of class
+ *                      OFFSET_RUNTIME  must determine offset at runtime
+ * Returns:
+ *      false   not a base
+ *      true    is a base
+ */
+
+bool InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
+{
+    //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars());
+    assert(!baseClass);
+    for (size_t j = 0; j < cd->interfaces.length; j++)
+    {
+        BaseClass *b = cd->interfaces.ptr[j];
+
+        //printf("\tX base %s\n", b->sym->toChars());
+        if (this == b->sym)
+        {
+            if (poffset)
+            {
+                // don't return incorrect offsets https://issues.dlang.org/show_bug.cgi?id=16980
+                *poffset = cd->sizeok == SIZEOKdone ? b->offset : OFFSET_FWDREF;
+            }
+            //printf("\tfound at offset %d\n", b->offset);
+            return true;
+        }
+        if (isBaseOf(b, poffset))
+            return true;
+    }
+
+    if (cd->baseClass && isBaseOf(cd->baseClass, poffset))
+        return true;
+
+    if (poffset)
+        *poffset = 0;
+    return false;
+}
+
+bool InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset)
+{
+    //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->sym->toChars());
+    for (size_t j = 0; j < bc->baseInterfaces.length; j++)
+    {
+        BaseClass *b = &bc->baseInterfaces.ptr[j];
+
+        //printf("\tY base %s\n", b->sym->toChars());
+        if (this == b->sym)
+        {
+            //printf("\tfound at offset %d\n", b->offset);
+            if (poffset)
+            {
+                *poffset = b->offset;
+            }
+            return true;
+        }
+        if (isBaseOf(b, poffset))
+        {
+            return true;
+        }
+    }
+    if (poffset)
+        *poffset = 0;
+    return false;
+}
+
+/****************************************
+ * Determine if slot 0 of the vtbl[] is reserved for something else.
+ * For class objects, yes, this is where the ClassInfo ptr goes.
+ * For COM interfaces, no.
+ * For non-COM interfaces, yes, this is where the Interface ptr goes.
+ */
+
+int InterfaceDeclaration::vtblOffset() const
+{
+    if (isCOMinterface() || isCPPinterface())
+        return 0;
+    return 1;
+}
+
+bool InterfaceDeclaration::isCOMinterface() const
+{
+    return com;
+}
+
+bool InterfaceDeclaration::isCPPinterface() const
+{
+    return cpp;
+}
+
+/*******************************************
+ */
+
+const char *InterfaceDeclaration::kind()
+{
+    return "interface";
+}
+
+
+/******************************** BaseClass *****************************/
+
+BaseClass::BaseClass()
+{
+    memset(this, 0, sizeof(BaseClass));
+}
+
+BaseClass::BaseClass(Type *type)
+{
+    //printf("BaseClass(this = %p, '%s')\n", this, type->toChars());
+    this->type = type;
+    this->sym = NULL;
+    this->offset = 0;
+
+    this->baseInterfaces.length = 0;
+    this->baseInterfaces.ptr = NULL;
+}
+
+/****************************************
+ * Fill in vtbl[] for base class based on member functions of class cd.
+ * Input:
+ *      vtbl            if !=NULL, fill it in
+ *      newinstance     !=0 means all entries must be filled in by members
+ *                      of cd, not members of any base classes of cd.
+ * Returns:
+ *      true if any entries were filled in by members of cd (not exclusively
+ *      by base classes)
+ */
+
+bool BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance)
+{
+    bool result = false;
+
+    //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", sym->toChars(), cd->toChars());
+    if (vtbl)
+        vtbl->setDim(sym->vtbl.dim);
+
+    // first entry is ClassInfo reference
+    for (size_t j = sym->vtblOffset(); j < sym->vtbl.dim; j++)
+    {
+        FuncDeclaration *ifd = sym->vtbl[j]->isFuncDeclaration();
+        FuncDeclaration *fd;
+        TypeFunction *tf;
+
+        //printf("        vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null");
+
+        assert(ifd);
+        // Find corresponding function in this class
+        tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL;
+        assert(tf);  // should always be non-null
+        fd = cd->findFunc(ifd->ident, tf);
+        if (fd && !fd->isAbstract())
+        {
+            //printf("            found\n");
+            // Check that calling conventions match
+            if (fd->linkage != ifd->linkage)
+                fd->error("linkage doesn't match interface function");
+
+            // Check that it is current
+            //printf("newinstance = %d fd->toParent() = %s ifd->toParent() = %s\n",
+                //newinstance, fd->toParent()->toChars(), ifd->toParent()->toChars());
+            if (newinstance && fd->toParent() != cd && ifd->toParent() == sym)
+                cd->error("interface function '%s' is not implemented", ifd->toFullSignature());
+
+            if (fd->toParent() == cd)
+                result = true;
+        }
+        else
+        {
+            //printf("            not found %p\n", fd);
+            // BUG: should mark this class as abstract?
+            if (!cd->isAbstract())
+                cd->error("interface function '%s' is not implemented", ifd->toFullSignature());
+
+            fd = NULL;
+        }
+        if (vtbl)
+            (*vtbl)[j] = fd;
+    }
+
+    return result;
+}
+
+void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces)
+{
+    //printf("+copyBaseInterfaces(), %s\n", sym->toChars());
+//    if (baseInterfaces.length)
+//      return;
+
+    baseInterfaces.length = sym->interfaces.length;
+    baseInterfaces.ptr = (BaseClass *)mem.xcalloc(baseInterfaces.length, sizeof(BaseClass));
+
+    //printf("%s.copyBaseInterfaces()\n", sym->toChars());
+    for (size_t i = 0; i < baseInterfaces.length; i++)
+    {
+        BaseClass *b = &baseInterfaces.ptr[i];
+        BaseClass *b2 = sym->interfaces.ptr[i];
+
+        assert(b2->vtbl.dim == 0);      // should not be filled yet
+        memcpy(b, b2, sizeof(BaseClass));
+
+        if (i)                          // single inheritance is i==0
+            vtblInterfaces->push(b);    // only need for M.I.
+        b->copyBaseInterfaces(vtblInterfaces);
+    }
+    //printf("-copyBaseInterfaces\n");
+}
diff --git a/gcc/d/dfrontend/declaration.c b/gcc/d/dfrontend/declaration.c
new file mode 100644
index 00000000000..568084981e0
--- /dev/null
+++ b/gcc/d/dfrontend/declaration.c
@@ -0,0 +1,2568 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/declaration.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "checkedint.h"
+
+#include "init.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "mtype.h"
+#include "template.h"
+#include "scope.h"
+#include "aggregate.h"
+#include "module.h"
+#include "import.h"
+#include "id.h"
+#include "expression.h"
+#include "statement.h"
+#include "ctfe.h"
+#include "target.h"
+#include "hdrgen.h"
+
+bool checkNestedRef(Dsymbol *s, Dsymbol *p);
+VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *initializerToExpression(Initializer *i, Type *t = NULL);
+Initializer *inferType(Initializer *init, Scope *sc);
+Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
+
+/************************************
+ * Check to see the aggregate type is nested and its context pointer is
+ * accessible from the current scope.
+ * Returns true if error occurs.
+ */
+bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t iStart = 0)
+{
+    Dsymbol *sparent = ad->toParent2();
+    Dsymbol *s = sc->func;
+    if (ad->isNested() && s)
+    {
+        //printf("ad = %p %s [%s], parent:%p\n", ad, ad->toChars(), ad->loc.toChars(), ad->parent);
+        //printf("sparent = %p %s [%s], parent: %s\n", sparent, sparent->toChars(), sparent->loc.toChars(), sparent->parent->toChars());
+        if (checkNestedRef(s, sparent))
+        {
+            error(loc, "cannot access frame pointer of %s", ad->toPrettyChars());
+            return true;
+        }
+    }
+
+    bool result = false;
+    for (size_t i = iStart; i < ad->fields.dim; i++)
+    {
+        VarDeclaration *vd = ad->fields[i];
+        Type *tb = vd->type->baseElemOf();
+        if (tb->ty == Tstruct)
+        {
+            result |= checkFrameAccess(loc, sc, ((TypeStruct *)tb)->sym);
+        }
+    }
+    return result;
+}
+
+/********************************* Declaration ****************************/
+
+Declaration::Declaration(Identifier *id)
+    : Dsymbol(id)
+{
+    type = NULL;
+    originalType = NULL;
+    storage_class = STCundefined;
+    protection = Prot(PROTundefined);
+    linkage = LINKdefault;
+    inuse = 0;
+    mangleOverride = NULL;
+}
+
+void Declaration::semantic(Scope *sc)
+{
+}
+
+const char *Declaration::kind()
+{
+    return "declaration";
+}
+
+d_uns64 Declaration::size(Loc loc)
+{
+    assert(type);
+    return type->size();
+}
+
+bool Declaration::isDelete()
+{
+    return false;
+}
+
+bool Declaration::isDataseg()
+{
+    return false;
+}
+
+bool Declaration::isThreadlocal()
+{
+    return false;
+}
+
+bool Declaration::isCodeseg()
+{
+    return false;
+}
+
+Prot Declaration::prot()
+{
+    return protection;
+}
+
+/*************************************
+ * Check to see if declaration can be modified in this context (sc).
+ * Issue error if not.
+ */
+
+int Declaration::checkModify(Loc loc, Scope *sc, Type *t, Expression *e1, int flag)
+{
+    VarDeclaration *v = isVarDeclaration();
+    if (v && v->canassign)
+        return 2;
+
+    if (isParameter() || isResult())
+    {
+        for (Scope *scx = sc; scx; scx = scx->enclosing)
+        {
+            if (scx->func == parent && (scx->flags & SCOPEcontract))
+            {
+                const char *s = isParameter() && parent->ident != Id::ensure ? "parameter" : "result";
+                if (!flag) error(loc, "cannot modify %s '%s' in contract", s, toChars());
+                return 2;   // do not report type related errors
+            }
+        }
+    }
+
+    if (v && (isCtorinit() || isField()))
+    {
+        // It's only modifiable if inside the right constructor
+        if ((storage_class & (STCforeach | STCref)) == (STCforeach | STCref))
+            return 2;
+        return modifyFieldVar(loc, sc, v, e1) ? 2 : 1;
+    }
+    return 1;
+}
+
+Dsymbol *Declaration::search(Loc loc, Identifier *ident, int flags)
+{
+    Dsymbol *s = Dsymbol::search(loc, ident, flags);
+    if (!s && type)
+    {
+        s = type->toDsymbol(_scope);
+        if (s)
+            s = s->search(loc, ident, flags);
+    }
+    return s;
+}
+
+
+/********************************* TupleDeclaration ****************************/
+
+TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects)
+    : Declaration(id)
+{
+    this->loc = loc;
+    this->type = NULL;
+    this->objects = objects;
+    this->isexp = false;
+    this->tupletype = NULL;
+}
+
+Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(0);
+    return NULL;
+}
+
+const char *TupleDeclaration::kind()
+{
+    return "tuple";
+}
+
+Type *TupleDeclaration::getType()
+{
+    /* If this tuple represents a type, return that type
+     */
+
+    //printf("TupleDeclaration::getType() %s\n", toChars());
+    if (isexp)
+        return NULL;
+    if (!tupletype)
+    {
+        /* It's only a type tuple if all the Object's are types
+         */
+        for (size_t i = 0; i < objects->dim; i++)
+        {
+            RootObject *o = (*objects)[i];
+            if (o->dyncast() != DYNCAST_TYPE)
+            {
+                //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast());
+                return NULL;
+            }
+        }
+
+        /* We know it's a type tuple, so build the TypeTuple
+         */
+        Types *types = (Types *)objects;
+        Parameters *args = new Parameters();
+        args->setDim(objects->dim);
+        OutBuffer buf;
+        int hasdeco = 1;
+        for (size_t i = 0; i < types->dim; i++)
+        {
+            Type *t = (*types)[i];
+            //printf("type = %s\n", t->toChars());
+#if 0
+            buf.printf("_%s_%d", ident->toChars(), i);
+            size_t len = buf.offset;
+            const char *name = (char *)buf.extractData();
+            Identifier *id = new Identifier(name, len);
+            Parameter *arg = new Parameter(STCin, t, id, NULL);
+#else
+            Parameter *arg = new Parameter(0, t, NULL, NULL);
+#endif
+            (*args)[i] = arg;
+            if (!t->deco)
+                hasdeco = 0;
+        }
+
+        tupletype = new TypeTuple(args);
+        if (hasdeco)
+            return tupletype->semantic(Loc(), NULL);
+    }
+
+    return tupletype;
+}
+
+Dsymbol *TupleDeclaration::toAlias2()
+{
+    //printf("TupleDeclaration::toAlias2() '%s' objects = %s\n", toChars(), objects->toChars());
+
+    for (size_t i = 0; i < objects->dim; i++)
+    {
+        RootObject *o = (*objects)[i];
+        if (Dsymbol *s = isDsymbol(o))
+        {
+            s = s->toAlias2();
+            (*objects)[i] = s;
+        }
+    }
+    return this;
+}
+
+bool TupleDeclaration::needThis()
+{
+    //printf("TupleDeclaration::needThis(%s)\n", toChars());
+    for (size_t i = 0; i < objects->dim; i++)
+    {
+        RootObject *o = (*objects)[i];
+        if (o->dyncast() == DYNCAST_EXPRESSION)
+        {
+            Expression *e = (Expression *)o;
+            if (e->op == TOKdsymbol)
+            {
+                DsymbolExp *ve = (DsymbolExp *)e;
+                Declaration *d = ve->s->isDeclaration();
+                if (d && d->needThis())
+                {
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+/********************************* AliasDeclaration ****************************/
+
+AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type)
+    : Declaration(id)
+{
+    //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type);
+    //printf("type = '%s'\n", type->toChars());
+    this->loc = loc;
+    this->type = type;
+    this->aliassym = NULL;
+    this->_import = NULL;
+    this->overnext = NULL;
+    assert(type);
+}
+
+AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s)
+    : Declaration(id)
+{
+    //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s);
+    assert(s != this);
+    this->loc = loc;
+    this->type = NULL;
+    this->aliassym = s;
+    this->_import = NULL;
+    this->overnext = NULL;
+    assert(s);
+}
+
+AliasDeclaration *AliasDeclaration::create(Loc loc, Identifier *id, Type *type)
+{
+    return new AliasDeclaration(loc, id, type);
+}
+
+Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("AliasDeclaration::syntaxCopy()\n");
+    assert(!s);
+    AliasDeclaration *sa =
+        type ? new AliasDeclaration(loc, ident, type->syntaxCopy())
+             : new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL));
+    sa->storage_class = storage_class;
+    return sa;
+}
+
+void AliasDeclaration::semantic(Scope *sc)
+{
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    assert(semanticRun <= PASSsemantic);
+
+    storage_class |= sc->stc & STCdeprecated;
+    protection = sc->protection;
+    userAttribDecl = sc->userAttribDecl;
+
+    if (!sc->func && inNonRoot())
+        return;
+
+    aliasSemantic(sc);
+}
+
+void AliasDeclaration::aliasSemantic(Scope *sc)
+{
+    //printf("AliasDeclaration::semantic() %s\n", toChars());
+    if (aliassym)
+    {
+        FuncDeclaration *fd = aliassym->isFuncLiteralDeclaration();
+        TemplateDeclaration *td = aliassym->isTemplateDeclaration();
+        if (fd || td && td->literal)
+        {
+            if (fd && fd->semanticRun >= PASSsemanticdone)
+                return;
+
+            Expression *e = new FuncExp(loc, aliassym);
+            e = ::semantic(e, sc);
+            if (e->op == TOKfunction)
+            {
+                FuncExp *fe = (FuncExp *)e;
+                aliassym = fe->td ? (Dsymbol *)fe->td : fe->fd;
+            }
+            else
+            {
+                aliassym = NULL;
+                type = Type::terror;
+            }
+            return;
+        }
+
+        if (aliassym->isTemplateInstance())
+            aliassym->semantic(sc);
+        return;
+    }
+    inuse = 1;
+
+    // Given:
+    //  alias foo.bar.abc def;
+    // it is not knowable from the syntax whether this is an alias
+    // for a type or an alias for a symbol. It is up to the semantic()
+    // pass to distinguish.
+    // If it is a type, then type is set and getType() will return that
+    // type. If it is a symbol, then aliassym is set and type is NULL -
+    // toAlias() will return aliasssym.
+
+    unsigned int errors = global.errors;
+    Type *oldtype = type;
+
+    // Ungag errors when not instantiated DeclDefs scope alias
+    Ungag ungag(global.gag);
+    //printf("%s parent = %s, gag = %d, instantiated = %d\n", toChars(), parent, global.gag, isInstantiated());
+    if (parent && global.gag && !isInstantiated() && !toParent2()->isFuncDeclaration())
+    {
+        //printf("%s type = %s\n", toPrettyChars(), type->toChars());
+        global.gag = 0;
+    }
+
+    /* This section is needed because Type::resolve() will:
+     *   const x = 3;
+     *   alias y = x;
+     * try to convert identifier x to 3.
+     */
+    Dsymbol *s = type->toDsymbol(sc);
+    if (errors != global.errors)
+    {
+        s = NULL;
+        type = Type::terror;
+    }
+    if (s && s == this)
+    {
+        error("cannot resolve");
+        s = NULL;
+        type = Type::terror;
+    }
+    if (!s || !s->isEnumMember())
+    {
+        Type *t;
+        Expression *e;
+        Scope *sc2 = sc;
+        if (storage_class & (STCref | STCnothrow | STCnogc | STCpure | STCdisable))
+        {
+            // For 'ref' to be attached to function types, and picked
+            // up by Type::resolve(), it has to go into sc.
+            sc2 = sc->push();
+            sc2->stc |= storage_class & (STCref | STCnothrow | STCnogc | STCpure | STCshared | STCdisable);
+        }
+        type = type->addSTC(storage_class);
+        type->resolve(loc, sc2, &e, &t, &s);
+        if (sc2 != sc)
+            sc2->pop();
+
+        if (e)  // Try to convert Expression to Dsymbol
+        {
+            s = getDsymbol(e);
+            if (!s)
+            {
+                if (e->op != TOKerror)
+                    error("cannot alias an expression %s", e->toChars());
+                t = Type::terror;
+            }
+        }
+        type = t;
+    }
+    if (s == this)
+    {
+        assert(global.errors);
+        type = Type::terror;
+        s = NULL;
+    }
+    if (!s) // it's a type alias
+    {
+        //printf("alias %s resolved to type %s\n", toChars(), type->toChars());
+        type = type->semantic(loc, sc);
+        aliassym = NULL;
+    }
+    else    // it's a symbolic alias
+    {
+        //printf("alias %s resolved to %s %s\n", toChars(), s->kind(), s->toChars());
+        type = NULL;
+        aliassym = s;
+    }
+    if (global.gag && errors != global.errors)
+    {
+        type = oldtype;
+        aliassym = NULL;
+    }
+    inuse = 0;
+    semanticRun = PASSsemanticdone;
+
+    if (Dsymbol *sx = overnext)
+    {
+        overnext = NULL;
+
+        if (!overloadInsert(sx))
+            ScopeDsymbol::multiplyDefined(Loc(), sx, this);
+    }
+}
+
+bool AliasDeclaration::overloadInsert(Dsymbol *s)
+{
+    //printf("[%s] AliasDeclaration::overloadInsert('%s') s = %s %s @ [%s]\n",
+    //    loc.toChars(), toChars(), s->kind(), s->toChars(), s->loc.toChars());
+
+    /** Aliases aren't overloadable themselves, but if their Aliasee is
+     *  overloadable they are converted to an overloadable Alias (either
+     *  FuncAliasDeclaration or OverDeclaration).
+     *
+     *  This is done by moving the Aliasee into such an overloadable alias
+     *  which is then used to replace the existing Aliasee. The original
+     *  Alias (_this_) remains a useless shell.
+     *
+     *  This is a horrible mess. It was probably done to avoid replacing
+     *  existing AST nodes and references, but it needs a major
+     *  simplification b/c it's too complex to maintain.
+     *
+     *  A simpler approach might be to merge any colliding symbols into a
+     *  simple Overload class (an array) and then later have that resolve
+     *  all collisions.
+     */
+    if (semanticRun >= PASSsemanticdone)
+    {
+        /* Semantic analysis is already finished, and the aliased entity
+         * is not overloadable.
+         */
+        if (type)
+            return false;
+
+        /* When s is added in member scope by static if, mixin("code") or others,
+         * aliassym is determined already. See the case in: test/compilable/test61.d
+         */
+        Dsymbol *sa = aliassym->toAlias();
+        if (FuncDeclaration *fd = sa->isFuncDeclaration())
+        {
+            FuncAliasDeclaration *fa = new FuncAliasDeclaration(ident, fd);
+            fa->protection = protection;
+            fa->parent = parent;
+            aliassym = fa;
+            return aliassym->overloadInsert(s);
+        }
+        if (TemplateDeclaration *td = sa->isTemplateDeclaration())
+        {
+            OverDeclaration *od = new OverDeclaration(ident, td);
+            od->protection = protection;
+            od->parent = parent;
+            aliassym = od;
+            return aliassym->overloadInsert(s);
+        }
+        if (OverDeclaration *od = sa->isOverDeclaration())
+        {
+            if (sa->ident != ident || sa->parent != parent)
+            {
+                od = new OverDeclaration(ident, od);
+                od->protection = protection;
+                od->parent = parent;
+                aliassym = od;
+            }
+            return od->overloadInsert(s);
+        }
+        if (OverloadSet *os = sa->isOverloadSet())
+        {
+            if (sa->ident != ident || sa->parent != parent)
+            {
+                os = new OverloadSet(ident, os);
+                // TODO: protection is lost here b/c OverloadSets have no protection attribute
+                // Might no be a practical issue, b/c the code below fails to resolve the overload anyhow.
+                // ----
+                // module os1;
+                // import a, b;
+                // private alias merged = foo; // private alias to overload set of a.foo and b.foo
+                // ----
+                // module os2;
+                // import a, b;
+                // public alias merged = bar; // public alias to overload set of a.bar and b.bar
+                // ----
+                // module bug;
+                // import os1, os2;
+                // void test() { merged(123); } // should only look at os2.merged
+                //
+                // os.protection = protection;
+                os->parent = parent;
+                aliassym = os;
+            }
+            os->push(s);
+            return true;
+        }
+        return false;
+    }
+
+    /* Don't know yet what the aliased symbol is, so assume it can
+     * be overloaded and check later for correctness.
+     */
+    if (overnext)
+        return overnext->overloadInsert(s);
+    if (s == this)
+        return true;
+    overnext = s;
+    return true;
+}
+
+const char *AliasDeclaration::kind()
+{
+    return "alias";
+}
+
+Type *AliasDeclaration::getType()
+{
+    if (type)
+        return type;
+    return toAlias()->getType();
+}
+
+Dsymbol *AliasDeclaration::toAlias()
+{
+    //printf("[%s] AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s', inuse = %d)\n",
+    //    loc.toChars(), toChars(), this, aliassym, aliassym ? aliassym->kind() : "", inuse);
+    assert(this != aliassym);
+    //static int count; if (++count == 10) *(char*)0=0;
+    if (inuse == 1 && type && _scope)
+    {
+        inuse = 2;
+        unsigned olderrors = global.errors;
+        Dsymbol *s = type->toDsymbol(_scope);
+        //printf("[%s] type = %s, s = %p, this = %p\n", loc.toChars(), type->toChars(), s, this);
+        if (global.errors != olderrors)
+            goto Lerr;
+        if (s)
+        {
+            s = s->toAlias();
+            if (global.errors != olderrors)
+                goto Lerr;
+            aliassym = s;
+            inuse = 0;
+        }
+        else
+        {
+            Type *t = type->semantic(loc, _scope);
+            if (t->ty == Terror)
+                goto Lerr;
+            if (global.errors != olderrors)
+                goto Lerr;
+            //printf("t = %s\n", t->toChars());
+            inuse = 0;
+        }
+    }
+    if (inuse)
+    {
+        error("recursive alias declaration");
+
+    Lerr:
+        // Avoid breaking "recursive alias" state during errors gagged
+        if (global.gag)
+            return this;
+
+        aliassym = new AliasDeclaration(loc, ident, Type::terror);
+        type = Type::terror;
+        return aliassym;
+    }
+
+    if (semanticRun >= PASSsemanticdone)
+    {
+        // semantic is already done.
+
+        // Do not see aliassym !is null, because of lambda aliases.
+
+        // Do not see type.deco !is null, even so "alias T = const int;` needs
+        // semantic analysis to take the storage class `const` as type qualifier.
+    }
+    else
+    {
+        if (_import && _import->_scope)
+        {
+            /* If this is an internal alias for selective/renamed import,
+             * load the module first.
+             */
+            _import->semantic(NULL);
+        }
+        if (_scope)
+        {
+            aliasSemantic(_scope);
+        }
+    }
+
+    inuse = 1;
+    Dsymbol *s = aliassym ? aliassym->toAlias() : this;
+    inuse = 0;
+    return s;
+}
+
+Dsymbol *AliasDeclaration::toAlias2()
+{
+    if (inuse)
+    {
+        error("recursive alias declaration");
+        return this;
+    }
+    inuse = 1;
+    Dsymbol *s  = aliassym ? aliassym->toAlias2() : this;
+    inuse = 0;
+    return s;
+}
+
+bool AliasDeclaration::isOverloadable()
+{
+    // assume overloadable until alias is resolved
+    return semanticRun < PASSsemanticdone ||
+        aliassym && aliassym->isOverloadable();
+}
+
+/****************************** OverDeclaration **************************/
+
+OverDeclaration::OverDeclaration(Identifier *ident, Dsymbol *s, bool hasOverloads)
+    : Declaration(ident)
+{
+    this->overnext = NULL;
+    this->aliassym = s;
+
+    this->hasOverloads = hasOverloads;
+    if (hasOverloads)
+    {
+        if (OverDeclaration *od = aliassym->isOverDeclaration())
+            this->hasOverloads = od->hasOverloads;
+    }
+    else
+    {
+        // for internal use
+        assert(!aliassym->isOverDeclaration());
+    }
+}
+
+const char *OverDeclaration::kind()
+{
+    return "overload alias";    // todo
+}
+
+void OverDeclaration::semantic(Scope *sc)
+{
+}
+
+bool OverDeclaration::equals(RootObject *o)
+{
+    if (this == o)
+        return true;
+
+    Dsymbol *s = isDsymbol(o);
+    if (!s)
+        return false;
+
+    OverDeclaration *od1 = this;
+    if (OverDeclaration *od2 = s->isOverDeclaration())
+    {
+        return od1->aliassym->equals(od2->aliassym) &&
+               od1->hasOverloads == od2->hasOverloads;
+    }
+    if (aliassym == s)
+    {
+        if (hasOverloads)
+            return true;
+        if (FuncDeclaration *fd = s->isFuncDeclaration())
+        {
+            return fd->isUnique() != NULL;
+        }
+        if (TemplateDeclaration *td = s->isTemplateDeclaration())
+        {
+            return td->overnext == NULL;
+        }
+    }
+    return false;
+}
+
+bool OverDeclaration::overloadInsert(Dsymbol *s)
+{
+    //printf("OverDeclaration::overloadInsert('%s') aliassym = %p, overnext = %p\n", s->toChars(), aliassym, overnext);
+    if (overnext)
+        return overnext->overloadInsert(s);
+    if (s == this)
+        return true;
+    overnext = s;
+    return true;
+}
+
+Dsymbol *OverDeclaration::toAlias()
+{
+    return this;
+}
+
+bool OverDeclaration::isOverloadable()
+{
+    return true;
+}
+
+Dsymbol *OverDeclaration::isUnique()
+{
+    if (!hasOverloads)
+    {
+        if (aliassym->isFuncDeclaration() ||
+            aliassym->isTemplateDeclaration())
+        {
+            return aliassym;
+        }
+    }
+
+  struct ParamUniqueSym
+  {
+    static int fp(void *param, Dsymbol *s)
+    {
+        Dsymbol **ps = (Dsymbol **)param;
+        if (*ps)
+        {
+            *ps = NULL;
+            return 1;   // ambiguous, done
+        }
+        else
+        {
+            *ps = s;
+            return 0;
+        }
+    }
+  };
+    Dsymbol *result = NULL;
+    overloadApply(aliassym, &result, &ParamUniqueSym::fp);
+    return result;
+}
+
+/********************************* VarDeclaration ****************************/
+
+VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init)
+    : Declaration(id)
+{
+    //printf("VarDeclaration('%s')\n", id->toChars());
+    assert(id);
+#ifdef DEBUG
+    if (!type && !init)
+    {
+        printf("VarDeclaration('%s')\n", id->toChars());
+        //*(char*)0=0;
+    }
+#endif
+    assert(type || init);
+    this->type = type;
+    this->_init = init;
+    this->loc = loc;
+    offset = 0;
+    isargptr = false;
+    alignment = 0;
+    ctorinit = 0;
+    aliassym = NULL;
+    onstack = false;
+    mynew = false;
+    canassign = 0;
+    overlapped = false;
+    overlapUnsafe = false;
+    doNotInferScope = false;
+    isdataseg = 0;
+    lastVar = NULL;
+    endlinnum = 0;
+    ctfeAdrOnStack = -1;
+    edtor = NULL;
+    range = NULL;
+
+    static unsigned nextSequenceNumber = 0;
+    this->sequenceNumber = ++nextSequenceNumber;
+}
+
+Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("VarDeclaration::syntaxCopy(%s)\n", toChars());
+    assert(!s);
+    VarDeclaration *v = new VarDeclaration(loc,
+            type ? type->syntaxCopy() : NULL,
+            ident,
+            _init ? _init->syntaxCopy() : NULL);
+    v->storage_class = storage_class;
+    return v;
+}
+
+
+void VarDeclaration::semantic(Scope *sc)
+{
+#if 0
+    printf("VarDeclaration::semantic('%s', parent = '%s') sem = %d\n", toChars(), sc->parent ? sc->parent->toChars() : NULL, sem);
+    printf(" type = %s\n", type ? type->toChars() : "null");
+    printf(" stc = x%x\n", sc->stc);
+    printf(" storage_class = x%llx\n", storage_class);
+    printf("linkage = %d\n", sc->linkage);
+    //if (strcmp(toChars(), "mul") == 0) halt();
+#endif
+
+//    if (semanticRun > PASSinit)
+//      return;
+//    semanticRun = PASSsemantic;
+
+    if (semanticRun >= PASSsemanticdone)
+        return;
+
+    Scope *scx = NULL;
+    if (_scope)
+    {
+        sc = _scope;
+        scx = sc;
+        _scope = NULL;
+    }
+
+    /* Pick up storage classes from context, but except synchronized,
+     * override, abstract, and final.
+     */
+    storage_class |= (sc->stc & ~(STCsynchronized | STCoverride | STCabstract | STCfinal));
+    if (storage_class & STCextern && _init)
+        error("extern symbols cannot have initializers");
+
+    userAttribDecl = sc->userAttribDecl;
+
+    AggregateDeclaration *ad = isThis();
+    if (ad)
+        storage_class |= ad->storage_class & STC_TYPECTOR;
+
+    /* If auto type inference, do the inference
+     */
+    int inferred = 0;
+    if (!type)
+    {
+        inuse++;
+
+        // Infering the type requires running semantic,
+        // so mark the scope as ctfe if required
+        bool needctfe = (storage_class & (STCmanifest | STCstatic)) != 0;
+        if (needctfe) sc = sc->startCTFE();
+
+        //printf("inferring type for %s with init %s\n", toChars(), _init->toChars());
+        _init = inferType(_init, sc);
+        type = initializerToExpression(_init)->type;
+
+        if (needctfe) sc = sc->endCTFE();
+
+        inuse--;
+        inferred = 1;
+
+        /* This is a kludge to support the existing syntax for RAII
+         * declarations.
+         */
+        storage_class &= ~STCauto;
+        originalType = type->syntaxCopy();
+    }
+    else
+    {
+        if (!originalType)
+            originalType = type->syntaxCopy();
+
+        /* Prefix function attributes of variable declaration can affect
+         * its type:
+         *      pure nothrow void function() fp;
+         *      static assert(is(typeof(fp) == void function() pure nothrow));
+         */
+        Scope *sc2 = sc->push();
+        sc2->stc |= (storage_class & STC_FUNCATTR);
+        inuse++;
+        type = type->semantic(loc, sc2);
+        inuse--;
+        sc2->pop();
+    }
+    //printf(" semantic type = %s\n", type ? type->toChars() : "null");
+    if (type->ty == Terror)
+        errors = true;
+
+    type->checkDeprecated(loc, sc);
+    linkage = sc->linkage;
+    this->parent = sc->parent;
+    //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars());
+    protection = sc->protection;
+
+    /* If scope's alignment is the default, use the type's alignment,
+     * otherwise the scope overrrides.
+     */
+    alignment = sc->alignment();
+    if (alignment == STRUCTALIGN_DEFAULT)
+        alignment = type->alignment();          // use type's alignment
+
+    //printf("sc->stc = %x\n", sc->stc);
+    //printf("storage_class = x%x\n", storage_class);
+
+    if (global.params.vcomplex)
+        type->checkComplexTransition(loc);
+
+    // Calculate type size + safety checks
+    if (sc->func && !sc->intypeof)
+    {
+        if ((storage_class & STCgshared) && !isMember())
+        {
+            if (sc->func->setUnsafe())
+                error("__gshared not allowed in safe functions; use shared");
+        }
+    }
+
+    Dsymbol *parent = toParent();
+
+    Type *tb = type->toBasetype();
+    Type *tbn = tb->baseElemOf();
+    if (tb->ty == Tvoid && !(storage_class & STClazy))
+    {
+        if (inferred)
+        {
+            error("type %s is inferred from initializer %s, and variables cannot be of type void",
+                type->toChars(), _init->toChars());
+        }
+        else
+            error("variables cannot be of type void");
+        type = Type::terror;
+        tb = type;
+    }
+    if (tb->ty == Tfunction)
+    {
+        error("cannot be declared to be a function");
+        type = Type::terror;
+        tb = type;
+    }
+    if (tb->ty == Tstruct)
+    {
+        TypeStruct *ts = (TypeStruct *)tb;
+        if (!ts->sym->members)
+        {
+            error("no definition of struct %s", ts->toChars());
+        }
+    }
+    if ((storage_class & STCauto) && !inferred)
+        error("storage class 'auto' has no effect if type is not inferred, did you mean 'scope'?");
+
+    if (tb->ty == Ttuple)
+    {
+        /* Instead, declare variables for each of the tuple elements
+         * and add those.
+         */
+        TypeTuple *tt = (TypeTuple *)tb;
+        size_t nelems = Parameter::dim(tt->arguments);
+        Expression *ie = (_init && !_init->isVoidInitializer()) ? initializerToExpression(_init) : NULL;
+        if (ie)
+            ie = ::semantic(ie, sc);
+
+        if (nelems > 0 && ie)
+        {
+            Expressions *iexps = new Expressions();
+            iexps->push(ie);
+
+            Expressions *exps = new Expressions();
+
+            for (size_t pos = 0; pos < iexps->dim; pos++)
+            {
+            Lexpand1:
+                Expression *e = (*iexps)[pos];
+                Parameter *arg = Parameter::getNth(tt->arguments, pos);
+                arg->type = arg->type->semantic(loc, sc);
+                //printf("[%d] iexps->dim = %d, ", pos, iexps->dim);
+                //printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars());
+                //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
+
+                if (e != ie)
+                {
+                if (iexps->dim > nelems)
+                    goto Lnomatch;
+                if (e->type->implicitConvTo(arg->type))
+                    continue;
+                }
+
+                if (e->op == TOKtuple)
+                {
+                    TupleExp *te = (TupleExp *)e;
+                    if (iexps->dim - 1 + te->exps->dim > nelems)
+                        goto Lnomatch;
+
+                    iexps->remove(pos);
+                    iexps->insert(pos, te->exps);
+                    (*iexps)[pos] = Expression::combine(te->e0, (*iexps)[pos]);
+                    goto Lexpand1;
+                }
+                else if (isAliasThisTuple(e))
+                {
+                    VarDeclaration *v = copyToTemp(0, "__tup", e);
+                    VarExp *ve = new VarExp(loc, v);
+                    ve->type = e->type;
+
+                    exps->setDim(1);
+                    (*exps)[0] = ve;
+                    expandAliasThisTuples(exps, 0);
+
+                    for (size_t u = 0; u < exps->dim ; u++)
+                    {
+                    Lexpand2:
+                        Expression *ee = (*exps)[u];
+                        arg = Parameter::getNth(tt->arguments, pos + u);
+                        arg->type = arg->type->semantic(loc, sc);
+                        //printf("[%d+%d] exps->dim = %d, ", pos, u, exps->dim);
+                        //printf("ee = (%s %s, %s), ", Token::tochars[ee->op], ee->toChars(), ee->type->toChars());
+                        //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
+
+                        size_t iexps_dim = iexps->dim - 1 + exps->dim;
+                        if (iexps_dim > nelems)
+                            goto Lnomatch;
+                        if (ee->type->implicitConvTo(arg->type))
+                            continue;
+
+                        if (expandAliasThisTuples(exps, u) != -1)
+                            goto Lexpand2;
+                    }
+
+                    if ((*exps)[0] != ve)
+                    {
+                        Expression *e0 = (*exps)[0];
+                        (*exps)[0] = new CommaExp(loc, new DeclarationExp(loc, v), e0);
+                        (*exps)[0]->type = e0->type;
+
+                        iexps->remove(pos);
+                        iexps->insert(pos, exps);
+                        goto Lexpand1;
+                    }
+                }
+            }
+            if (iexps->dim < nelems)
+                goto Lnomatch;
+
+            ie = new TupleExp(_init->loc, iexps);
+        }
+Lnomatch:
+
+        if (ie && ie->op == TOKtuple)
+        {
+            TupleExp *te = (TupleExp *)ie;
+            size_t tedim = te->exps->dim;
+            if (tedim != nelems)
+            {
+                ::error(loc, "tuple of %d elements cannot be assigned to tuple of %d elements", (int)tedim, (int)nelems);
+                for (size_t u = tedim; u < nelems; u++) // fill dummy expression
+                    te->exps->push(new ErrorExp());
+            }
+        }
+
+        Objects *exps = new Objects();
+        exps->setDim(nelems);
+        for (size_t i = 0; i < nelems; i++)
+        {
+            Parameter *arg = Parameter::getNth(tt->arguments, i);
+
+            OutBuffer buf;
+            buf.printf("__%s_field_%llu", ident->toChars(), (ulonglong)i);
+            const char *name = buf.extractString();
+            Identifier *id = Identifier::idPool(name);
+
+            Initializer *ti;
+            if (ie)
+            {
+                Expression *einit = ie;
+                if (ie->op == TOKtuple)
+                {
+                    TupleExp *te = (TupleExp *)ie;
+                    einit = (*te->exps)[i];
+                    if (i == 0)
+                        einit = Expression::combine(te->e0, einit);
+                }
+                ti = new ExpInitializer(einit->loc, einit);
+            }
+            else
+                ti = _init ? _init->syntaxCopy() : NULL;
+
+            VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti);
+            v->storage_class |= STCtemp | storage_class;
+            if (arg->storageClass & STCparameter)
+                v->storage_class |= arg->storageClass;
+            //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars());
+            v->semantic(sc);
+
+            if (sc->scopesym)
+            {
+                //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars());
+                if (sc->scopesym->members)
+                    sc->scopesym->members->push(v);
+            }
+
+            Expression *e = new DsymbolExp(loc, v);
+            (*exps)[i] = e;
+        }
+        TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps);
+        v2->parent = this->parent;
+        v2->isexp = true;
+        aliassym = v2;
+        semanticRun = PASSsemanticdone;
+        return;
+    }
+
+    /* Storage class can modify the type
+     */
+    type = type->addStorageClass(storage_class);
+
+    /* Adjust storage class to reflect type
+     */
+    if (type->isConst())
+    {
+        storage_class |= STCconst;
+        if (type->isShared())
+            storage_class |= STCshared;
+    }
+    else if (type->isImmutable())
+        storage_class |= STCimmutable;
+    else if (type->isShared())
+        storage_class |= STCshared;
+    else if (type->isWild())
+        storage_class |= STCwild;
+
+    if (StorageClass stc = storage_class & (STCsynchronized | STCoverride | STCabstract | STCfinal))
+    {
+        if (stc == STCfinal)
+            error("cannot be final, perhaps you meant const?");
+        else
+        {
+            OutBuffer buf;
+            stcToBuffer(&buf, stc);
+            error("cannot be %s", buf.peekString());
+        }
+        storage_class &= ~stc;  // strip off
+    }
+
+    if (storage_class & STCscope)
+    {
+        StorageClass stc = storage_class & (STCstatic | STCextern | STCmanifest | STCtls | STCgshared);
+        if (stc)
+        {
+            OutBuffer buf;
+            stcToBuffer(&buf, stc);
+            error("cannot be 'scope' and '%s'", buf.peekString());
+        }
+        else if (isMember())
+        {
+            error("field cannot be 'scope'");
+        }
+        else if (!type->hasPointers())
+        {
+            storage_class &= ~STCscope;     // silently ignore; may occur in generic code
+        }
+    }
+
+    if (storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared | STCctfe))
+    {
+    }
+    else
+    {
+        AggregateDeclaration *aad = parent->isAggregateDeclaration();
+        if (aad)
+        {
+            if (global.params.vfield &&
+                storage_class & (STCconst | STCimmutable) && _init && !_init->isVoidInitializer())
+            {
+                const char *p = loc.toChars();
+                const char *s = (storage_class & STCimmutable) ? "immutable" : "const";
+                fprintf(global.stdmsg, "%s: %s.%s is %s field\n", p ? p : "", ad->toPrettyChars(), toChars(), s);
+            }
+            storage_class |= STCfield;
+            if (tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor)
+            {
+                if (!isThisDeclaration() && !_init)
+                    aad->noDefaultCtor = true;
+            }
+        }
+
+        InterfaceDeclaration *id = parent->isInterfaceDeclaration();
+        if (id)
+        {
+            error("field not allowed in interface");
+        }
+        else if (aad && aad->sizeok == SIZEOKdone)
+        {
+            error("cannot be further field because it will change the determined %s size", aad->toChars());
+        }
+
+        /* Templates cannot add fields to aggregates
+         */
+        TemplateInstance *ti = parent->isTemplateInstance();
+        if (ti)
+        {
+            // Take care of nested templates
+            while (1)
+            {
+                TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance();
+                if (!ti2)
+                    break;
+                ti = ti2;
+            }
+
+            // If it's a member template
+            AggregateDeclaration *ad2 = ti->tempdecl->isMember();
+            if (ad2 && storage_class != STCundefined)
+            {
+                error("cannot use template to add field to aggregate '%s'", ad2->toChars());
+            }
+        }
+    }
+
+    if ((storage_class & (STCref | STCparameter | STCforeach | STCtemp | STCresult)) == STCref && ident != Id::This)
+    {
+        error("only parameters or foreach declarations can be ref");
+    }
+
+    if (type->hasWild())
+    {
+        if (storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield) ||
+            isDataseg()
+            )
+        {
+            error("only parameters or stack based variables can be inout");
+        }
+        FuncDeclaration *func = sc->func;
+        if (func)
+        {
+            if (func->fes)
+                func = func->fes->func;
+            bool isWild = false;
+            for (FuncDeclaration *fd = func; fd; fd = fd->toParent2()->isFuncDeclaration())
+            {
+                if (((TypeFunction *)fd->type)->iswild)
+                {
+                    isWild = true;
+                    break;
+                }
+            }
+            if (!isWild)
+            {
+                error("inout variables can only be declared inside inout functions");
+            }
+        }
+    }
+
+    if (!(storage_class & (STCctfe | STCref | STCresult)) && tbn->ty == Tstruct &&
+        ((TypeStruct *)tbn)->sym->noDefaultCtor)
+    {
+        if (!_init)
+        {
+            if (isField())
+            {
+                /* For fields, we'll check the constructor later to make sure it is initialized
+                 */
+                storage_class |= STCnodefaultctor;
+            }
+            else if (storage_class & STCparameter)
+                ;
+            else
+                error("default construction is disabled for type %s", type->toChars());
+        }
+    }
+
+    FuncDeclaration *fd = parent->isFuncDeclaration();
+    if (type->isscope() && !(storage_class & STCnodtor))
+    {
+        if (storage_class & (STCfield | STCout | STCref | STCstatic | STCmanifest | STCtls | STCgshared) || !fd)
+        {
+            error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope");
+        }
+
+        if (!(storage_class & STCscope))
+        {
+            if (!(storage_class & STCparameter) && ident != Id::withSym)
+                error("reference to scope class must be scope");
+        }
+    }
+
+    // Calculate type size + safety checks
+    if (sc->func && !sc->intypeof)
+    {
+        if (_init && _init->isVoidInitializer() && type->hasPointers()) // get type size
+        {
+            if (sc->func->setUnsafe())
+                error("void initializers for pointers not allowed in safe functions");
+        }
+        else if (!_init &&
+                 !(storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield | STCparameter)) &&
+                 type->hasVoidInitPointers())
+        {
+            if (sc->func->setUnsafe())
+                error("void initializers for pointers not allowed in safe functions");
+        }
+    }
+
+    if (!_init && !fd)
+    {
+        // If not mutable, initializable by constructor only
+        storage_class |= STCctorinit;
+    }
+
+    if (_init)
+        storage_class |= STCinit;     // remember we had an explicit initializer
+    else if (storage_class & STCmanifest)
+        error("manifest constants must have initializers");
+
+    bool isBlit = false;
+    d_uns64 sz = 0;
+    if (!_init && !sc->inunion && !(storage_class & (STCstatic | STCgshared | STCextern)) && fd &&
+        (!(storage_class & (STCfield | STCin | STCforeach | STCparameter | STCresult))
+         || (storage_class & STCout)) &&
+        (sz = type->size()) != 0)
+    {
+        // Provide a default initializer
+        //printf("Providing default initializer for '%s'\n", toChars());
+        if (sz == SIZE_INVALID && type->ty != Terror)
+            error("size of type %s is invalid", type->toChars());
+
+        Type *tv = type;
+        while (tv->ty == Tsarray)    // Don't skip Tenum
+            tv = tv->nextOf();
+        if (tv->needsNested())
+        {
+            /* Nested struct requires valid enclosing frame pointer.
+             * In StructLiteralExp::toElem(), it's calculated.
+             */
+            assert(tv->toBasetype()->ty == Tstruct);
+            checkFrameAccess(loc, sc, ((TypeStruct *)tbn)->sym);
+
+            Expression *e = tv->defaultInitLiteral(loc);
+            e = new BlitExp(loc, new VarExp(loc, this), e);
+            e = ::semantic(e, sc);
+            _init = new ExpInitializer(loc, e);
+            goto Ldtor;
+        }
+        if (tv->ty == Tstruct && ((TypeStruct *)tv)->sym->zeroInit == 1)
+        {
+            /* If a struct is all zeros, as a special case
+             * set it's initializer to the integer 0.
+             * In AssignExp::toElem(), we check for this and issue
+             * a memset() to initialize the struct.
+             * Must do same check in interpreter.
+             */
+            Expression *e = new IntegerExp(loc, 0, Type::tint32);
+            e = new BlitExp(loc, new VarExp(loc, this), e);
+            e->type = type;         // don't type check this, it would fail
+            _init = new ExpInitializer(loc, e);
+            goto Ldtor;
+        }
+        if (type->baseElemOf()->ty == Tvoid)
+        {
+            error("%s does not have a default initializer", type->toChars());
+        }
+        else if (Expression *e = type->defaultInit(loc))
+        {
+            _init = new ExpInitializer(loc, e);
+        }
+        // Default initializer is always a blit
+        isBlit = true;
+    }
+
+    if (_init)
+    {
+        sc = sc->push();
+        sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCnogc | STCref | STCdisable);
+
+        ExpInitializer *ei = _init->isExpInitializer();
+        if (ei)     // Bugzilla 13424: Preset the required type to fail in FuncLiteralDeclaration::semantic3
+            ei->exp = inferType(ei->exp, type);
+
+        // If inside function, there is no semantic3() call
+        if (sc->func || sc->intypeof == 1)
+        {
+            // If local variable, use AssignExp to handle all the various
+            // possibilities.
+            if (fd &&
+                !(storage_class & (STCmanifest | STCstatic | STCtls | STCgshared | STCextern)) &&
+                !_init->isVoidInitializer())
+            {
+                //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars());
+                if (!ei)
+                {
+                    ArrayInitializer *ai = _init->isArrayInitializer();
+                    Expression *e;
+                    if (ai && tb->ty == Taarray)
+                        e = ai->toAssocArrayLiteral();
+                    else
+                        e = initializerToExpression(_init);
+                    if (!e)
+                    {
+                        // Run semantic, but don't need to interpret
+                        _init = ::semantic(_init, sc, type, INITnointerpret);
+                        e = initializerToExpression(_init);
+                        if (!e)
+                        {
+                            error("is not a static and cannot have static initializer");
+                            return;
+                        }
+                    }
+                    ei = new ExpInitializer(_init->loc, e);
+                    _init = ei;
+                }
+
+                Expression *exp = ei->exp;
+                Expression *e1 = new VarExp(loc, this);
+                if (isBlit)
+                    exp = new BlitExp(loc, e1, exp);
+                else
+                    exp = new ConstructExp(loc, e1, exp);
+                canassign++;
+                exp = ::semantic(exp, sc);
+                canassign--;
+                exp = exp->optimize(WANTvalue);
+
+                if (exp->op == TOKerror)
+                {
+                    _init = new ErrorInitializer();
+                    ei = NULL;
+                }
+                else
+                    ei->exp = exp;
+
+                if (ei && isScope())
+                {
+                    Expression *ex = ei->exp;
+                    while (ex->op == TOKcomma)
+                        ex = ((CommaExp *)ex)->e2;
+                    if (ex->op == TOKblit || ex->op == TOKconstruct)
+                        ex = ((AssignExp *)ex)->e2;
+                    if (ex->op == TOKnew)
+                    {
+                        // See if initializer is a NewExp that can be allocated on the stack
+                        NewExp *ne = (NewExp *)ex;
+                        if (type->toBasetype()->ty == Tclass)
+                        {
+                            if (ne->newargs && ne->newargs->dim > 1)
+                            {
+                                mynew = true;
+                            }
+                            else
+                            {
+                                ne->onstack = true;
+                                onstack = true;
+                            }
+                        }
+                    }
+                    else if (ex->op == TOKfunction)
+                    {
+                        // or a delegate that doesn't escape a reference to the function
+                        FuncDeclaration *f = ((FuncExp *)ex)->fd;
+                        f->tookAddressOf--;
+                    }
+                }
+            }
+            else
+            {
+                // Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof
+                _init = ::semantic(_init, sc, type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
+            }
+        }
+        else if (parent->isAggregateDeclaration())
+        {
+            _scope = scx ? scx : sc->copy();
+            _scope->setNoFree();
+        }
+        else if (storage_class & (STCconst | STCimmutable | STCmanifest) ||
+                 type->isConst() || type->isImmutable())
+        {
+            /* Because we may need the results of a const declaration in a
+             * subsequent type, such as an array dimension, before semantic2()
+             * gets ordinarily run, try to run semantic2() now.
+             * Ignore failure.
+             */
+
+            if (!inferred)
+            {
+                unsigned errors = global.errors;
+                inuse++;
+                if (ei)
+                {
+                    Expression *exp = ei->exp->syntaxCopy();
+
+                    bool needctfe = isDataseg() || (storage_class & STCmanifest);
+                    if (needctfe) sc = sc->startCTFE();
+                    exp = ::semantic(exp, sc);
+                    exp = resolveProperties(sc, exp);
+                    if (needctfe) sc = sc->endCTFE();
+
+                    Type *tb2 = type->toBasetype();
+                    Type *ti = exp->type->toBasetype();
+
+                    /* The problem is the following code:
+                     *  struct CopyTest {
+                     *     double x;
+                     *     this(double a) { x = a * 10.0;}
+                     *     this(this) { x += 2.0; }
+                     *  }
+                     *  const CopyTest z = CopyTest(5.3);  // ok
+                     *  const CopyTest w = z;              // not ok, postblit not run
+                     *  static assert(w.x == 55.0);
+                     * because the postblit doesn't get run on the initialization of w.
+                     */
+                    if (ti->ty == Tstruct)
+                    {
+                        StructDeclaration *sd = ((TypeStruct *)ti)->sym;
+                        /* Look to see if initializer involves a copy constructor
+                         * (which implies a postblit)
+                         */
+                         // there is a copy constructor
+                         // and exp is the same struct
+                        if (sd->postblit &&
+                            tb2->toDsymbol(NULL) == sd)
+                        {
+                            // The only allowable initializer is a (non-copy) constructor
+                            if (exp->isLvalue())
+                                error("of type struct %s uses this(this), which is not allowed in static initialization", tb2->toChars());
+                        }
+                    }
+                    ei->exp = exp;
+                }
+                _init = ::semantic(_init, sc, type, INITinterpret);
+                inuse--;
+                if (global.errors > errors)
+                {
+                    _init = new ErrorInitializer();
+                    type = Type::terror;
+                }
+            }
+            else
+            {
+                _scope = scx ? scx : sc->copy();
+                _scope->setNoFree();
+            }
+        }
+        sc = sc->pop();
+    }
+
+Ldtor:
+    /* Build code to execute destruction, if necessary
+     */
+    edtor = callScopeDtor(sc);
+    if (edtor)
+    {
+        if (sc->func && storage_class & (STCstatic | STCgshared))
+            edtor = ::semantic(edtor, sc->_module->_scope);
+        else
+            edtor = ::semantic(edtor, sc);
+
+#if 0 // currently disabled because of std.stdio.stdin, stdout and stderr
+        if (isDataseg() && !(storage_class & STCextern))
+            error("static storage variables cannot have destructors");
+#endif
+    }
+
+    semanticRun = PASSsemanticdone;
+
+    if (type->toBasetype()->ty == Terror)
+        errors = true;
+
+    if (sc->scopesym && !sc->scopesym->isAggregateDeclaration())
+    {
+        for (ScopeDsymbol *sym = sc->scopesym; sym && endlinnum == 0;
+             sym = sym->parent ? sym->parent->isScopeDsymbol() : NULL)
+            endlinnum = sym->endlinnum;
+    }
+}
+
+void VarDeclaration::semantic2(Scope *sc)
+{
+    if (semanticRun < PASSsemanticdone && inuse)
+        return;
+
+    //printf("VarDeclaration::semantic2('%s')\n", toChars());
+
+    if (_init && !toParent()->isFuncDeclaration())
+    {
+        inuse++;
+#if 0
+        ExpInitializer *ei = _init->isExpInitializer();
+        if (ei)
+        {
+            ei->exp->print();
+            printf("type = %p\n", ei->exp->type);
+        }
+#endif
+        // Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof
+        _init = ::semantic(_init, sc, type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
+        inuse--;
+    }
+    if (_init && storage_class & STCmanifest)
+    {
+        /* Cannot initializer enums with CTFE classreferences and addresses of struct literals.
+         * Scan initializer looking for them. Issue error if found.
+         */
+        if (ExpInitializer *ei = _init->isExpInitializer())
+        {
+            struct EnumInitializer
+            {
+                static bool arrayHasInvalidEnumInitializer(Expressions *elems)
+                {
+                    for (size_t i = 0; i < elems->dim; i++)
+                    {
+                        Expression *e = (*elems)[i];
+                        if (e && hasInvalidEnumInitializer(e))
+                            return true;
+                    }
+                    return false;
+                }
+
+                static bool hasInvalidEnumInitializer(Expression *e)
+                {
+                    if (e->op == TOKclassreference)
+                        return true;
+                    if (e->op == TOKaddress && ((AddrExp *)e)->e1->op == TOKstructliteral)
+                        return true;
+                    if (e->op == TOKarrayliteral)
+                        return arrayHasInvalidEnumInitializer(((ArrayLiteralExp *)e)->elements);
+                    if (e->op == TOKstructliteral)
+                        return arrayHasInvalidEnumInitializer(((StructLiteralExp *)e)->elements);
+                    if (e->op == TOKassocarrayliteral)
+                    {
+                        AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
+                        return arrayHasInvalidEnumInitializer(ae->values) ||
+                            arrayHasInvalidEnumInitializer(ae->keys);
+                    }
+                    return false;
+                }
+            };
+            if (EnumInitializer::hasInvalidEnumInitializer(ei->exp))
+                error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead.");
+        }
+    }
+    else if (_init && isThreadlocal())
+    {
+        if ((type->ty == Tclass) && type->isMutable() && !type->isShared())
+        {
+            ExpInitializer *ei = _init->isExpInitializer();
+            if (ei && ei->exp->op == TOKclassreference)
+                error("is mutable. Only const or immutable class thread local variable are allowed, not %s", type->toChars());
+        }
+        else if (type->ty == Tpointer && type->nextOf()->ty == Tstruct && type->nextOf()->isMutable() &&!type->nextOf()->isShared())
+        {
+            ExpInitializer *ei = _init->isExpInitializer();
+            if (ei && ei->exp->op == TOKaddress && ((AddrExp *)ei->exp)->e1->op == TOKstructliteral)
+            {
+                error("is a pointer to mutable struct. Only pointers to const, immutable or shared struct thread local variable are allowed, not %s", type->toChars());
+            }
+        }
+    }
+    semanticRun = PASSsemantic2done;
+}
+
+void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
+{
+    //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad->toChars(), toChars());
+
+    if (aliassym)
+    {
+        // If this variable was really a tuple, set the offsets for the tuple fields
+        TupleDeclaration *v2 = aliassym->isTupleDeclaration();
+        assert(v2);
+        for (size_t i = 0; i < v2->objects->dim; i++)
+        {
+            RootObject *o = (*v2->objects)[i];
+            assert(o->dyncast() == DYNCAST_EXPRESSION);
+            Expression *e = (Expression *)o;
+            assert(e->op == TOKdsymbol);
+            DsymbolExp *se = (DsymbolExp *)e;
+            se->s->setFieldOffset(ad, poffset, isunion);
+        }
+        return;
+    }
+
+    if (!isField())
+        return;
+    assert(!(storage_class & (STCstatic | STCextern | STCparameter | STCtls)));
+
+    //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad->toChars(), toChars());
+
+    /* Fields that are tuples appear both as part of TupleDeclarations and
+     * as members. That means ignore them if they are already a field.
+     */
+    if (offset)
+    {
+        // already a field
+        *poffset = ad->structsize;  // Bugzilla 13613
+        return;
+    }
+    for (size_t i = 0; i < ad->fields.dim; i++)
+    {
+        if (ad->fields[i] == this)
+        {
+            // already a field
+            *poffset = ad->structsize;  // Bugzilla 13613
+            return;
+        }
+    }
+
+    // Check for forward referenced types which will fail the size() call
+    Type *t = type->toBasetype();
+    if (storage_class & STCref)
+    {
+        // References are the size of a pointer
+        t = Type::tvoidptr;
+    }
+    Type *tv = t->baseElemOf();
+    if (tv->ty == Tstruct)
+    {
+        TypeStruct *ts = (TypeStruct *)tv;
+        assert(ts->sym != ad);   // already checked in ad->determineFields()
+        if (!ts->sym->determineSize(loc))
+        {
+            type = Type::terror;
+            errors = true;
+            return;
+        }
+    }
+
+    // List in ad->fields. Even if the type is error, it's necessary to avoid
+    // pointless error diagnostic "more initializers than fields" on struct literal.
+    ad->fields.push(this);
+
+    if (t->ty == Terror)
+        return;
+
+    const d_uns64 sz = t->size(loc);
+    assert(sz != SIZE_INVALID && sz < UINT32_MAX);
+    unsigned memsize = (unsigned)sz;                 // size of member
+    unsigned memalignsize = Target::fieldalign(t);   // size of member for alignment purposes
+
+    offset = AggregateDeclaration::placeField(poffset, memsize, memalignsize, alignment,
+                &ad->structsize, &ad->alignsize, isunion);
+
+    //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
+
+    //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad->toChars(), offset, memsize);
+}
+
+const char *VarDeclaration::kind()
+{
+    return "variable";
+}
+
+Dsymbol *VarDeclaration::toAlias()
+{
+    //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym);
+    if ((!type || !type->deco) && _scope)
+        semantic(_scope);
+
+    assert(this != aliassym);
+    Dsymbol *s = aliassym ? aliassym->toAlias() : this;
+    return s;
+}
+
+AggregateDeclaration *VarDeclaration::isThis()
+{
+    AggregateDeclaration *ad = NULL;
+
+    if (!(storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter |
+                           STCtls | STCgshared | STCctfe)))
+    {
+        for (Dsymbol *s = this; s; s = s->parent)
+        {
+            ad = s->isMember();
+            if (ad)
+                break;
+            if (!s->parent || !s->parent->isTemplateMixin()) break;
+        }
+    }
+    return ad;
+}
+
+bool VarDeclaration::needThis()
+{
+    //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class);
+    return isField();
+}
+
+bool VarDeclaration::isExport()
+{
+    return protection.kind == PROTexport;
+}
+
+bool VarDeclaration::isImportedSymbol()
+{
+    if (protection.kind == PROTexport && !_init &&
+        (storage_class & STCstatic || parent->isModule()))
+        return true;
+    return false;
+}
+
+/*******************************************
+ * Helper function for the expansion of manifest constant.
+ */
+Expression *VarDeclaration::expandInitializer(Loc loc)
+{
+    assert((storage_class & STCmanifest) && _init);
+
+    Expression *e = getConstInitializer();
+    if (!e)
+    {
+        ::error(loc, "cannot make expression out of initializer for %s", toChars());
+        return new ErrorExp();
+    }
+
+    e = e->copy();
+    e->loc = loc;    // for better error message
+    return e;
+}
+
+void VarDeclaration::checkCtorConstInit()
+{
+#if 0 /* doesn't work if more than one static ctor */
+    if (ctorinit == 0 && isCtorinit() && !isField())
+        error("missing initializer in static constructor for const variable");
+#endif
+}
+
+bool lambdaCheckForNestedRef(Expression *e, Scope *sc);
+
+/************************************
+ * Check to see if this variable is actually in an enclosing function
+ * rather than the current one.
+ * Returns true if error occurs.
+ */
+bool VarDeclaration::checkNestedReference(Scope *sc, Loc loc)
+{
+    //printf("VarDeclaration::checkNestedReference() %s\n", toChars());
+    if (sc->intypeof == 1 || (sc->flags & SCOPEctfe))
+        return false;
+    if (!parent || parent == sc->parent)
+        return false;
+    if (isDataseg() || (storage_class & STCmanifest))
+        return false;
+
+    // The current function
+    FuncDeclaration *fdthis = sc->parent->isFuncDeclaration();
+    if (!fdthis)
+        return false;   // out of function scope
+
+    Dsymbol *p = toParent2();
+
+    // Function literals from fdthis to p must be delegates
+    checkNestedRef(fdthis, p);
+
+    // The function that this variable is in
+    FuncDeclaration *fdv = p->isFuncDeclaration();
+    if (!fdv || fdv == fdthis)
+        return false;
+
+    // Add fdthis to nestedrefs[] if not already there
+    for (size_t i = 0; 1; i++)
+    {
+        if (i == nestedrefs.dim)
+        {
+            nestedrefs.push(fdthis);
+            break;
+        }
+        if (nestedrefs[i] == fdthis)
+            break;
+    }
+
+    /* __require and __ensure will always get called directly,
+     * so they never make outer functions closure.
+     */
+    if (fdthis->ident == Id::require || fdthis->ident == Id::ensure)
+        return false;
+
+    //printf("\tfdv = %s\n", fdv->toChars());
+    //printf("\tfdthis = %s\n", fdthis->toChars());
+    if (loc.filename)
+    {
+        int lv = fdthis->getLevel(loc, sc, fdv);
+        if (lv == -2)   // error
+            return true;
+    }
+
+    // Add this to fdv->closureVars[] if not already there
+    for (size_t i = 0; 1; i++)
+    {
+        if (i == fdv->closureVars.dim)
+        {
+            if (!sc->intypeof && !(sc->flags & SCOPEcompile))
+                fdv->closureVars.push(this);
+            break;
+        }
+        if (fdv->closureVars[i] == this)
+            break;
+    }
+
+    //printf("fdthis is %s\n", fdthis->toChars());
+    //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars());
+    // __dollar creates problems because it isn't a real variable Bugzilla 3326
+    if (ident == Id::dollar)
+    {
+        ::error(loc, "cannnot use $ inside a function literal");
+        return true;
+    }
+
+    if (ident == Id::withSym)       // Bugzilla 1759
+    {
+        ExpInitializer *ez = _init->isExpInitializer();
+        assert(ez);
+        Expression *e = ez->exp;
+        if (e->op == TOKconstruct || e->op == TOKblit)
+            e = ((AssignExp *)e)->e2;
+        return lambdaCheckForNestedRef(e, sc);
+    }
+
+    return false;
+}
+
+/*******************************************
+ * If variable has a constant expression initializer, get it.
+ * Otherwise, return NULL.
+ */
+
+Expression *VarDeclaration::getConstInitializer(bool needFullType)
+{
+    assert(type && _init);
+
+    // Ungag errors when not speculative
+    unsigned oldgag = global.gag;
+    if (global.gag)
+    {
+        Dsymbol *sym = toParent()->isAggregateDeclaration();
+        if (sym && !sym->isSpeculative())
+            global.gag = 0;
+    }
+
+    if (_scope)
+    {
+        inuse++;
+        _init = ::semantic(_init, _scope, type, INITinterpret);
+        _scope = NULL;
+        inuse--;
+    }
+    Expression *e = initializerToExpression(_init, needFullType ? type : NULL);
+
+    global.gag = oldgag;
+    return e;
+}
+
+/*************************************
+ * Return true if we can take the address of this variable.
+ */
+
+bool VarDeclaration::canTakeAddressOf()
+{
+    return !(storage_class & STCmanifest);
+}
+
+
+/*******************************
+ * Does symbol go into data segment?
+ * Includes extern variables.
+ */
+
+bool VarDeclaration::isDataseg()
+{
+#if 0
+    printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars());
+    printf("%llx, isModule: %p, isTemplateInstance: %p, isNspace: %p\n",
+           storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance(), parent->isNspace());
+    printf("parent = '%s'\n", parent->toChars());
+#endif
+    if (isdataseg == 0) // the value is not cached
+    {
+        isdataseg = 2; // The Variables does not go into the datasegment
+
+        if (!canTakeAddressOf())
+        {
+            return false;
+        }
+
+        Dsymbol *parent = toParent();
+        if (!parent && !(storage_class & STCstatic))
+        {
+            error("forward referenced");
+            type = Type::terror;
+        }
+        else if (storage_class & (STCstatic | STCextern | STCtls | STCgshared) ||
+                 parent->isModule() || parent->isTemplateInstance() || parent->isNspace())
+        {
+            isdataseg = 1; // It is in the DataSegment
+        }
+    }
+
+    return (isdataseg == 1);
+}
+
+/************************************
+ * Does symbol go into thread local storage?
+ */
+
+bool VarDeclaration::isThreadlocal()
+{
+    //printf("VarDeclaration::isThreadlocal(%p, '%s')\n", this, toChars());
+    /* Data defaults to being thread-local. It is not thread-local
+     * if it is immutable, const or shared.
+     */
+    bool i = isDataseg() &&
+        !(storage_class & (STCimmutable | STCconst | STCshared | STCgshared));
+    //printf("\treturn %d\n", i);
+    return i;
+}
+
+/********************************************
+ * Can variable be read and written by CTFE?
+ */
+
+bool VarDeclaration::isCTFE()
+{
+    return (storage_class & STCctfe) != 0; // || !isDataseg();
+}
+
+bool VarDeclaration::isOverlappedWith(VarDeclaration *v)
+{
+    const d_uns64 vsz = v->type->size();
+    const d_uns64 tsz = type->size();
+    assert(vsz != SIZE_INVALID && tsz != SIZE_INVALID);
+    return offset < v->offset + vsz &&
+        v->offset < offset + tsz;
+}
+
+bool VarDeclaration::hasPointers()
+{
+    //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty);
+    return (!isDataseg() && type->hasPointers());
+}
+
+/******************************************
+ * Return true if variable needs to call the destructor.
+ */
+
+bool VarDeclaration::needsScopeDtor()
+{
+    //printf("VarDeclaration::needsScopeDtor() %s\n", toChars());
+    return edtor && !(storage_class & STCnodtor);
+}
+
+
+/******************************************
+ * If a variable has a scope destructor call, return call for it.
+ * Otherwise, return NULL.
+ */
+
+Expression *VarDeclaration::callScopeDtor(Scope *sc)
+{
+    //printf("VarDeclaration::callScopeDtor() %s\n", toChars());
+
+    // Destruction of STCfield's is handled by buildDtor()
+    if (storage_class & (STCnodtor | STCref | STCout | STCfield))
+    {
+        return NULL;
+    }
+
+    Expression *e = NULL;
+
+    // Destructors for structs and arrays of structs
+    Type *tv = type->baseElemOf();
+    if (tv->ty == Tstruct)
+    {
+        StructDeclaration *sd = ((TypeStruct *)tv)->sym;
+        if (!sd->dtor || sd->errors)
+           return NULL;
+
+        const d_uns64 sz = type->size();
+        assert(sz != SIZE_INVALID);
+        if (!sz)
+            return NULL;
+
+        if (type->toBasetype()->ty == Tstruct)
+        {
+            // v.__xdtor()
+            e = new VarExp(loc, this);
+
+            /* This is a hack so we can call destructors on const/immutable objects.
+             * Need to add things like "const ~this()" and "immutable ~this()" to
+             * fix properly.
+             */
+            e->type = e->type->mutableOf();
+
+            e = new DotVarExp(loc, e, sd->dtor, false);
+            e = new CallExp(loc, e);
+        }
+        else
+        {
+            // _ArrayDtor(v[0 .. n])
+            e = new VarExp(loc, this);
+
+            const d_uns64 sdsz = sd->type->size();
+            assert(sdsz != SIZE_INVALID && sdsz != 0);
+            const d_uns64 n = sz / sdsz;
+            e = new SliceExp(loc, e, new IntegerExp(loc, 0, Type::tsize_t),
+                                     new IntegerExp(loc, n, Type::tsize_t));
+            // Prevent redundant bounds check
+            ((SliceExp *)e)->upperIsInBounds = true;
+            ((SliceExp *)e)->lowerIsLessThanUpper = true;
+
+            // This is a hack so we can call destructors on const/immutable objects.
+            e->type = sd->type->arrayOf();
+
+            e = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), e);
+        }
+        return e;
+    }
+
+    // Destructors for classes
+    if (storage_class & (STCauto | STCscope) && !(storage_class & STCparameter))
+    {
+        for (ClassDeclaration *cd = type->isClassHandle();
+             cd;
+             cd = cd->baseClass)
+        {
+            /* We can do better if there's a way with onstack
+             * classes to determine if there's no way the monitor
+             * could be set.
+             */
+            //if (cd->isInterfaceDeclaration())
+                //error("interface %s cannot be scope", cd->toChars());
+
+            if (cd->cpp)
+            {
+                // Destructors are not supported on extern(C++) classes
+                break;
+            }
+            if (mynew || onstack || cd->dtors.dim) // if any destructors
+            {
+                // delete this;
+                Expression *ec;
+
+                ec = new VarExp(loc, this);
+                e = new DeleteExp(loc, ec, true);
+                e->type = Type::tvoid;
+                break;
+            }
+        }
+    }
+    return e;
+}
+
+/**********************************
+ * Determine if `this` has a lifetime that lasts past
+ * the destruction of `v`
+ * Params:
+ *  v = variable to test against
+ * Returns:
+ *  true if it does
+ */
+bool VarDeclaration::enclosesLifetimeOf(VarDeclaration *v) const
+{
+    return sequenceNumber < v->sequenceNumber;
+}
+
+/******************************************
+ */
+
+void ObjectNotFound(Identifier *id)
+{
+    Type::error(Loc(), "%s not found. object.d may be incorrectly installed or corrupt.", id->toChars());
+    fatal();
+}
+
+/******************************** SymbolDeclaration ********************************/
+
+SymbolDeclaration::SymbolDeclaration(Loc loc, StructDeclaration *dsym)
+        : Declaration(dsym->ident)
+{
+    this->loc = loc;
+    this->dsym = dsym;
+    storage_class |= STCconst;
+}
+
+/********************************* TypeInfoDeclaration ****************************/
+
+TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo)
+    : VarDeclaration(Loc(), Type::dtypeinfo->type, tinfo->getTypeInfoIdent(), NULL)
+{
+    this->tinfo = tinfo;
+    storage_class = STCstatic | STCgshared;
+    protection = Prot(PROTpublic);
+    linkage = LINKc;
+    alignment = Target::ptrsize;
+}
+
+TypeInfoDeclaration *TypeInfoDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoDeclaration(tinfo);
+}
+
+Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(0);          // should never be produced by syntax
+    return NULL;
+}
+
+void TypeInfoDeclaration::semantic(Scope *sc)
+{
+    assert(linkage == LINKc);
+}
+
+const char *TypeInfoDeclaration::toChars()
+{
+    //printf("TypeInfoDeclaration::toChars() tinfo = %s\n", tinfo->toChars());
+    OutBuffer buf;
+    buf.writestring("typeid(");
+    buf.writestring(tinfo->toChars());
+    buf.writeByte(')');
+    return buf.extractString();
+}
+
+/***************************** TypeInfoConstDeclaration **********************/
+
+TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfoconst)
+    {
+        ObjectNotFound(Id::TypeInfo_Const);
+    }
+    type = Type::typeinfoconst->type;
+}
+
+TypeInfoConstDeclaration *TypeInfoConstDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoConstDeclaration(tinfo);
+}
+
+/***************************** TypeInfoInvariantDeclaration **********************/
+
+TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfoinvariant)
+    {
+        ObjectNotFound(Id::TypeInfo_Invariant);
+    }
+    type = Type::typeinfoinvariant->type;
+}
+
+TypeInfoInvariantDeclaration *TypeInfoInvariantDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoInvariantDeclaration(tinfo);
+}
+
+/***************************** TypeInfoSharedDeclaration **********************/
+
+TypeInfoSharedDeclaration::TypeInfoSharedDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfoshared)
+    {
+        ObjectNotFound(Id::TypeInfo_Shared);
+    }
+    type = Type::typeinfoshared->type;
+}
+
+TypeInfoSharedDeclaration *TypeInfoSharedDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoSharedDeclaration(tinfo);
+}
+
+/***************************** TypeInfoWildDeclaration **********************/
+
+TypeInfoWildDeclaration::TypeInfoWildDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfowild)
+    {
+        ObjectNotFound(Id::TypeInfo_Wild);
+    }
+    type = Type::typeinfowild->type;
+}
+
+TypeInfoWildDeclaration *TypeInfoWildDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoWildDeclaration(tinfo);
+}
+
+/***************************** TypeInfoStructDeclaration **********************/
+
+TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfostruct)
+    {
+        ObjectNotFound(Id::TypeInfo_Struct);
+    }
+    type = Type::typeinfostruct->type;
+}
+
+TypeInfoStructDeclaration *TypeInfoStructDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoStructDeclaration(tinfo);
+}
+
+/***************************** TypeInfoClassDeclaration ***********************/
+
+TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfoclass)
+    {
+        ObjectNotFound(Id::TypeInfo_Class);
+    }
+    type = Type::typeinfoclass->type;
+}
+
+TypeInfoClassDeclaration *TypeInfoClassDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoClassDeclaration(tinfo);
+}
+
+/***************************** TypeInfoInterfaceDeclaration *******************/
+
+TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfointerface)
+    {
+        ObjectNotFound(Id::TypeInfo_Interface);
+    }
+    type = Type::typeinfointerface->type;
+}
+
+TypeInfoInterfaceDeclaration *TypeInfoInterfaceDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoInterfaceDeclaration(tinfo);
+}
+
+/***************************** TypeInfoPointerDeclaration *********************/
+
+TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfopointer)
+    {
+        ObjectNotFound(Id::TypeInfo_Pointer);
+    }
+    type = Type::typeinfopointer->type;
+}
+
+TypeInfoPointerDeclaration *TypeInfoPointerDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoPointerDeclaration(tinfo);
+}
+
+/***************************** TypeInfoArrayDeclaration ***********************/
+
+TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfoarray)
+    {
+        ObjectNotFound(Id::TypeInfo_Array);
+    }
+    type = Type::typeinfoarray->type;
+}
+
+TypeInfoArrayDeclaration *TypeInfoArrayDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoArrayDeclaration(tinfo);
+}
+
+/***************************** TypeInfoStaticArrayDeclaration *****************/
+
+TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfostaticarray)
+    {
+        ObjectNotFound(Id::TypeInfo_StaticArray);
+    }
+    type = Type::typeinfostaticarray->type;
+}
+
+TypeInfoStaticArrayDeclaration *TypeInfoStaticArrayDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoStaticArrayDeclaration(tinfo);
+}
+
+/***************************** TypeInfoAssociativeArrayDeclaration ************/
+
+TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfoassociativearray)
+    {
+        ObjectNotFound(Id::TypeInfo_AssociativeArray);
+    }
+    type = Type::typeinfoassociativearray->type;
+}
+
+TypeInfoAssociativeArrayDeclaration *TypeInfoAssociativeArrayDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoAssociativeArrayDeclaration(tinfo);
+}
+
+/***************************** TypeInfoVectorDeclaration ***********************/
+
+TypeInfoVectorDeclaration::TypeInfoVectorDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfovector)
+    {
+        ObjectNotFound(Id::TypeInfo_Vector);
+    }
+    type = Type::typeinfovector->type;
+}
+
+TypeInfoVectorDeclaration *TypeInfoVectorDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoVectorDeclaration(tinfo);
+}
+
+/***************************** TypeInfoEnumDeclaration ***********************/
+
+TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfoenum)
+    {
+        ObjectNotFound(Id::TypeInfo_Enum);
+    }
+    type = Type::typeinfoenum->type;
+}
+
+TypeInfoEnumDeclaration *TypeInfoEnumDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoEnumDeclaration(tinfo);
+}
+
+/***************************** TypeInfoFunctionDeclaration ********************/
+
+TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfofunction)
+    {
+        ObjectNotFound(Id::TypeInfo_Function);
+    }
+    type = Type::typeinfofunction->type;
+}
+
+TypeInfoFunctionDeclaration *TypeInfoFunctionDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoFunctionDeclaration(tinfo);
+}
+
+/***************************** TypeInfoDelegateDeclaration ********************/
+
+TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfodelegate)
+    {
+        ObjectNotFound(Id::TypeInfo_Delegate);
+    }
+    type = Type::typeinfodelegate->type;
+}
+
+TypeInfoDelegateDeclaration *TypeInfoDelegateDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoDelegateDeclaration(tinfo);
+}
+
+/***************************** TypeInfoTupleDeclaration **********************/
+
+TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo)
+{
+    if (!Type::typeinfotypelist)
+    {
+        ObjectNotFound(Id::TypeInfo_Tuple);
+    }
+    type = Type::typeinfotypelist->type;
+}
+
+TypeInfoTupleDeclaration *TypeInfoTupleDeclaration::create(Type *tinfo)
+{
+    return new TypeInfoTupleDeclaration(tinfo);
+}
+
+/********************************* ThisDeclaration ****************************/
+
+// For the "this" parameter to member functions
+
+ThisDeclaration::ThisDeclaration(Loc loc, Type *t)
+   : VarDeclaration(loc, t, Id::This, NULL)
+{
+    storage_class |= STCnodtor;
+}
+
+Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(0);          // should never be produced by syntax
+    return NULL;
+}
+
diff --git a/gcc/d/dfrontend/declaration.h b/gcc/d/dfrontend/declaration.h
new file mode 100644
index 00000000000..fe20b56072b
--- /dev/null
+++ b/gcc/d/dfrontend/declaration.h
@@ -0,0 +1,902 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/declaration.h
+ */
+
+#ifndef DMD_DECLARATION_H
+#define DMD_DECLARATION_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+#include "mtype.h"
+#include "objc.h"
+
+class Expression;
+class Statement;
+class LabelDsymbol;
+class Initializer;
+class Module;
+class ForeachStatement;
+class FuncDeclaration;
+class ExpInitializer;
+class StructDeclaration;
+struct InterState;
+struct CompiledCtfeFunction;
+struct ObjcSelector;
+
+enum LINK;
+enum TOK;
+enum MATCH;
+enum PURE;
+enum PINLINE;
+
+#define STCundefined    0LL
+#define STCstatic       1LL
+#define STCextern       2LL
+#define STCconst        4LL
+#define STCfinal        8LL
+#define STCabstract     0x10LL
+#define STCparameter    0x20LL
+#define STCfield        0x40LL
+#define STCoverride     0x80LL
+#define STCauto         0x100LL
+#define STCsynchronized 0x200LL
+#define STCdeprecated   0x400LL
+#define STCin           0x800LL         // in parameter
+#define STCout          0x1000LL        // out parameter
+#define STClazy         0x2000LL        // lazy parameter
+#define STCforeach      0x4000LL        // variable for foreach loop
+#define STCvariadic     0x10000LL       // the 'variadic' parameter in: T foo(T a, U b, V variadic...)
+#define STCctorinit     0x20000LL       // can only be set inside constructor
+#define STCtemplateparameter  0x40000LL // template parameter
+#define STCscope        0x80000LL
+#define STCimmutable    0x100000LL
+#define STCref          0x200000LL
+#define STCinit         0x400000LL      // has explicit initializer
+#define STCmanifest     0x800000LL      // manifest constant
+#define STCnodtor       0x1000000LL     // don't run destructor
+#define STCnothrow      0x2000000LL     // never throws exceptions
+#define STCpure         0x4000000LL     // pure function
+#define STCtls          0x8000000LL     // thread local
+#define STCalias        0x10000000LL    // alias parameter
+#define STCshared       0x20000000LL    // accessible from multiple threads
+// accessible from multiple threads
+// but not typed as "shared"
+#define STCgshared      0x40000000LL
+#define STCwild         0x80000000LL    // for "wild" type constructor
+#define STC_TYPECTOR    (STCconst | STCimmutable | STCshared | STCwild)
+#define STC_FUNCATTR    (STCref | STCnothrow | STCnogc | STCpure | STCproperty | STCsafe | STCtrusted | STCsystem)
+
+#define STCproperty      0x100000000LL
+#define STCsafe          0x200000000LL
+#define STCtrusted       0x400000000LL
+#define STCsystem        0x800000000LL
+#define STCctfe          0x1000000000LL  // can be used in CTFE, even if it is static
+#define STCdisable       0x2000000000LL  // for functions that are not callable
+#define STCresult        0x4000000000LL  // for result variables passed to out contracts
+#define STCnodefaultctor 0x8000000000LL  // must be set inside constructor
+#define STCtemp          0x10000000000LL // temporary variable
+#define STCrvalue        0x20000000000LL // force rvalue for variables
+#define STCnogc          0x40000000000LL // @nogc
+#define STCvolatile      0x80000000000LL // destined for volatile in the back end
+#define STCreturn        0x100000000000LL // 'return ref' or 'return scope' for function parameters
+#define STCautoref       0x200000000000LL // Mark for the already deduced 'auto ref' parameter
+#define STCinference     0x400000000000LL // do attribute inference
+#define STCexptemp       0x800000000000LL // temporary variable that has lifetime restricted to an expression
+#define STCmaybescope    0x1000000000000LL // parameter might be 'scope'
+#define STCscopeinferred 0x2000000000000LL // 'scope' has been inferred and should not be part of mangling
+
+const StorageClass STCStorageClass = (STCauto | STCscope | STCstatic | STCextern | STCconst | STCfinal |
+    STCabstract | STCsynchronized | STCdeprecated | STCoverride | STClazy | STCalias |
+    STCout | STCin |
+    STCmanifest | STCimmutable | STCshared | STCwild | STCnothrow | STCnogc | STCpure | STCref | STCtls |
+    STCgshared | STCproperty | STCsafe | STCtrusted | STCsystem | STCdisable);
+
+struct Match
+{
+    int count;                  // number of matches found
+    MATCH last;                 // match level of lastf
+    FuncDeclaration *lastf;     // last matching function we found
+    FuncDeclaration *nextf;     // current matching function
+    FuncDeclaration *anyf;      // pick a func, any func, to use for error recovery
+};
+
+void functionResolve(Match *m, Dsymbol *fd, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs);
+int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *));
+
+void ObjectNotFound(Identifier *id);
+
+/**************************************************************/
+
+class Declaration : public Dsymbol
+{
+public:
+    Type *type;
+    Type *originalType;         // before semantic analysis
+    StorageClass storage_class;
+    Prot protection;
+    LINK linkage;
+    int inuse;                  // used to detect cycles
+    const char *mangleOverride;      // overridden symbol with pragma(mangle, "...")
+
+    Declaration(Identifier *id);
+    void semantic(Scope *sc);
+    const char *kind();
+    d_uns64 size(Loc loc);
+    int checkModify(Loc loc, Scope *sc, Type *t, Expression *e1, int flag);
+
+    Dsymbol *search(Loc loc, Identifier *ident, int flags = SearchLocalsOnly);
+
+    bool isStatic() { return (storage_class & STCstatic) != 0; }
+    virtual bool isDelete();
+    virtual bool isDataseg();
+    virtual bool isThreadlocal();
+    virtual bool isCodeseg();
+    bool isCtorinit()     { return (storage_class & STCctorinit) != 0; }
+    bool isFinal()        { return (storage_class & STCfinal) != 0; }
+    bool isAbstract()     { return (storage_class & STCabstract) != 0; }
+    bool isConst()        { return (storage_class & STCconst) != 0; }
+    bool isImmutable()    { return (storage_class & STCimmutable) != 0; }
+    bool isWild()         { return (storage_class & STCwild) != 0; }
+    bool isAuto()         { return (storage_class & STCauto) != 0; }
+    bool isScope()        { return (storage_class & STCscope) != 0; }
+    bool isSynchronized() { return (storage_class & STCsynchronized) != 0; }
+    bool isParameter()    { return (storage_class & STCparameter) != 0; }
+    bool isDeprecated()   { return (storage_class & STCdeprecated) != 0; }
+    bool isOverride()     { return (storage_class & STCoverride) != 0; }
+    bool isResult()       { return (storage_class & STCresult) != 0; }
+    bool isField()        { return (storage_class & STCfield) != 0; }
+
+    bool isIn()    { return (storage_class & STCin) != 0; }
+    bool isOut()   { return (storage_class & STCout) != 0; }
+    bool isRef()   { return (storage_class & STCref) != 0; }
+
+    Prot prot();
+
+    Declaration *isDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+class TupleDeclaration : public Declaration
+{
+public:
+    Objects *objects;
+    bool isexp;                 // true: expression tuple
+
+    TypeTuple *tupletype;       // !=NULL if this is a type tuple
+
+    TupleDeclaration(Loc loc, Identifier *ident, Objects *objects);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    const char *kind();
+    Type *getType();
+    Dsymbol *toAlias2();
+    bool needThis();
+
+    TupleDeclaration *isTupleDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+class AliasDeclaration : public Declaration
+{
+public:
+    Dsymbol *aliassym;
+    Dsymbol *overnext;          // next in overload list
+    Dsymbol *_import;           // !=NULL if unresolved internal alias for selective import
+
+    AliasDeclaration(Loc loc, Identifier *ident, Type *type);
+    AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s);
+    static AliasDeclaration *create(Loc loc, Identifier *id, Type *type);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    void aliasSemantic(Scope *sc);
+    bool overloadInsert(Dsymbol *s);
+    const char *kind();
+    Type *getType();
+    Dsymbol *toAlias();
+    Dsymbol *toAlias2();
+    bool isOverloadable();
+
+    AliasDeclaration *isAliasDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+class OverDeclaration : public Declaration
+{
+public:
+    Dsymbol *overnext;          // next in overload list
+    Dsymbol *aliassym;
+    bool hasOverloads;
+
+    OverDeclaration(Identifier *ident, Dsymbol *s, bool hasOverloads = true);
+    const char *kind();
+    void semantic(Scope *sc);
+    bool equals(RootObject *o);
+    bool overloadInsert(Dsymbol *s);
+
+    Dsymbol *toAlias();
+    Dsymbol *isUnique();
+    bool isOverloadable();
+
+    OverDeclaration *isOverDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+class VarDeclaration : public Declaration
+{
+public:
+    Initializer *_init;
+    unsigned offset;
+    unsigned sequenceNumber;     // order the variables are declared
+    FuncDeclarations nestedrefs; // referenced by these lexically nested functions
+    bool isargptr;              // if parameter that _argptr points to
+    structalign_t alignment;
+    bool ctorinit;              // it has been initialized in a ctor
+    bool onstack;               // it is a class that was allocated on the stack
+    bool mynew;                 // it is a class new'd with custom operator new
+    int canassign;              // it can be assigned to
+    bool overlapped;            // if it is a field and has overlapping
+    bool overlapUnsafe;         // if it is an overlapping field and the overlaps are unsafe
+    bool doNotInferScope;       // do not infer 'scope' for this variable
+    unsigned char isdataseg;    // private data for isDataseg
+    Dsymbol *aliassym;          // if redone as alias to another symbol
+    VarDeclaration *lastVar;    // Linked list of variables for goto-skips-init detection
+    unsigned endlinnum;         // line number of end of scope that this var lives in
+
+    // When interpreting, these point to the value (NULL if value not determinable)
+    // The index of this variable on the CTFE stack, -1 if not allocated
+    int ctfeAdrOnStack;
+    Expression *edtor;          // if !=NULL, does the destruction of the variable
+    IntRange *range;            // if !NULL, the variable is known to be within the range
+
+    VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+    void semantic2(Scope *sc);
+    const char *kind();
+    AggregateDeclaration *isThis();
+    bool needThis();
+    bool isExport();
+    bool isImportedSymbol();
+    bool isDataseg();
+    bool isThreadlocal();
+    bool isCTFE();
+    bool isOverlappedWith(VarDeclaration *v);
+    bool hasPointers();
+    bool canTakeAddressOf();
+    bool needsScopeDtor();
+    bool enclosesLifetimeOf(VarDeclaration *v) const;
+    Expression *callScopeDtor(Scope *sc);
+    Expression *getConstInitializer(bool needFullType = true);
+    Expression *expandInitializer(Loc loc);
+    void checkCtorConstInit();
+    bool checkNestedReference(Scope *sc, Loc loc);
+    Dsymbol *toAlias();
+    // Eliminate need for dynamic_cast
+    VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+// This is a shell around a back end symbol
+
+class SymbolDeclaration : public Declaration
+{
+public:
+    StructDeclaration *dsym;
+
+    SymbolDeclaration(Loc loc, StructDeclaration *dsym);
+
+    // Eliminate need for dynamic_cast
+    SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoDeclaration : public VarDeclaration
+{
+public:
+    Type *tinfo;
+
+    TypeInfoDeclaration(Type *tinfo);
+    static TypeInfoDeclaration *create(Type *tinfo);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    const char *toChars();
+
+    TypeInfoDeclaration *isTypeInfoDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoStructDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoStructDeclaration(Type *tinfo);
+    static TypeInfoStructDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoClassDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoClassDeclaration(Type *tinfo);
+    static TypeInfoClassDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoInterfaceDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoInterfaceDeclaration(Type *tinfo);
+    static TypeInfoInterfaceDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoPointerDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoPointerDeclaration(Type *tinfo);
+    static TypeInfoPointerDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoArrayDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoArrayDeclaration(Type *tinfo);
+    static TypeInfoArrayDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoStaticArrayDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoStaticArrayDeclaration(Type *tinfo);
+    static TypeInfoStaticArrayDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoAssociativeArrayDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoAssociativeArrayDeclaration(Type *tinfo);
+    static TypeInfoAssociativeArrayDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoEnumDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoEnumDeclaration(Type *tinfo);
+    static TypeInfoEnumDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoFunctionDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoFunctionDeclaration(Type *tinfo);
+    static TypeInfoFunctionDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoDelegateDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoDelegateDeclaration(Type *tinfo);
+    static TypeInfoDelegateDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoTupleDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoTupleDeclaration(Type *tinfo);
+    static TypeInfoTupleDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoConstDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoConstDeclaration(Type *tinfo);
+    static TypeInfoConstDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoInvariantDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoInvariantDeclaration(Type *tinfo);
+    static TypeInfoInvariantDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoSharedDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoSharedDeclaration(Type *tinfo);
+    static TypeInfoSharedDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoWildDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoWildDeclaration(Type *tinfo);
+    static TypeInfoWildDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoVectorDeclaration : public TypeInfoDeclaration
+{
+public:
+    TypeInfoVectorDeclaration(Type *tinfo);
+    static TypeInfoVectorDeclaration *create(Type *tinfo);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+class ThisDeclaration : public VarDeclaration
+{
+public:
+    ThisDeclaration(Loc loc, Type *t);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    ThisDeclaration *isThisDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+enum ILS
+{
+    ILSuninitialized,   // not computed yet
+    ILSno,              // cannot inline
+    ILSyes,             // can inline
+};
+
+/**************************************************************/
+
+enum BUILTIN
+{
+    BUILTINunknown = -1,        // not known if this is a builtin
+    BUILTINno,                  // this is not a builtin
+    BUILTINyes,                 // this is a builtin
+};
+
+Expression *eval_builtin(Loc loc, FuncDeclaration *fd, Expressions *arguments);
+BUILTIN isBuiltin(FuncDeclaration *fd);
+
+typedef Expression *(*builtin_fp)(Loc loc, FuncDeclaration *fd, Expressions *arguments);
+void add_builtin(const char *mangle, builtin_fp fp);
+void builtin_init();
+
+#define FUNCFLAGpurityInprocess    1    // working on determining purity
+#define FUNCFLAGsafetyInprocess    2    // working on determining safety
+#define FUNCFLAGnothrowInprocess   4    // working on determining nothrow
+#define FUNCFLAGnogcInprocess      8    // working on determining @nogc
+#define FUNCFLAGreturnInprocess 0x10    // working on inferring 'return' for parameters
+#define FUNCFLAGinlineScanned   0x20    // function has been scanned for inline possibilities
+#define FUNCFLAGinferScope      0x40    // infer 'scope' for parameters
+
+class FuncDeclaration : public Declaration
+{
+public:
+    Types *fthrows;                     // Array of Type's of exceptions (not used)
+    Statement *frequire;
+    Statement *fensure;
+    Statement *fbody;
+
+    FuncDeclarations foverrides;        // functions this function overrides
+    FuncDeclaration *fdrequire;         // function that does the in contract
+    FuncDeclaration *fdensure;          // function that does the out contract
+
+    const char *mangleString;           // mangled symbol created from mangleExact()
+
+    Identifier *outId;                  // identifier for out statement
+    VarDeclaration *vresult;            // variable corresponding to outId
+    LabelDsymbol *returnLabel;          // where the return goes
+
+    // used to prevent symbols in different
+    // scopes from having the same name
+    DsymbolTable *localsymtab;
+    VarDeclaration *vthis;              // 'this' parameter (member and nested)
+    VarDeclaration *v_arguments;        // '_arguments' parameter
+    ObjcSelector* selector;             // Objective-C method selector (member function only)
+    VarDeclaration *v_argptr;           // '_argptr' variable
+    VarDeclarations *parameters;        // Array of VarDeclaration's for parameters
+    DsymbolTable *labtab;               // statement label symbol table
+    Dsymbol *overnext;                  // next in overload list
+    FuncDeclaration *overnext0;         // next in overload list (only used during IFTI)
+    Loc endloc;                         // location of closing curly bracket
+    int vtblIndex;                      // for member functions, index into vtbl[]
+    bool naked;                         // true if naked
+    bool generated;                     // true if function was generated by the compiler rather than
+                                        // supplied by the user
+    ILS inlineStatusStmt;
+    ILS inlineStatusExp;
+    PINLINE inlining;
+
+    CompiledCtfeFunction *ctfeCode;     // Compiled code for interpreter
+    int inlineNest;                     // !=0 if nested inline
+    bool isArrayOp;                     // true if array operation
+    // true if errors in semantic3 this function's frame ptr
+    bool semantic3Errors;
+    ForeachStatement *fes;              // if foreach body, this is the foreach
+    BaseClass* interfaceVirtual;        // if virtual, but only appears in interface vtbl[]
+    bool introducing;                   // true if 'introducing' function
+    // if !=NULL, then this is the type
+    // of the 'introducing' function
+    // this one is overriding
+    Type *tintro;
+    bool inferRetType;                  // true if return type is to be inferred
+    StorageClass storage_class2;        // storage class for template onemember's
+
+    // Things that should really go into Scope
+
+    // 1 if there's a return exp; statement
+    // 2 if there's a throw statement
+    // 4 if there's an assert(0)
+    // 8 if there's inline asm
+    // 16 if there are multiple return statements
+    int hasReturnExp;
+
+    // Support for NRVO (named return value optimization)
+    bool nrvo_can;                      // true means we can do it
+    VarDeclaration *nrvo_var;           // variable to replace with shidden
+    Symbol *shidden;                    // hidden pointer passed to function
+
+    ReturnStatements *returns;
+
+    GotoStatements *gotos;              // Gotos with forward references
+
+    // set if this is a known, builtin function we can evaluate at compile time
+    BUILTIN builtin;
+
+    // set if someone took the address of this function
+    int tookAddressOf;
+    bool requiresClosure;               // this function needs a closure
+
+    // local variables in this function which are referenced by nested functions
+    VarDeclarations closureVars;
+    // Sibling nested functions which called this one
+    FuncDeclarations siblingCallers;
+
+    FuncDeclarations *inlinedNestedCallees;
+
+    unsigned flags;                     // FUNCFLAGxxxxx
+
+    FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type);
+    static FuncDeclaration *create(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    bool functionSemantic();
+    bool functionSemantic3();
+    bool checkForwardRef(Loc loc);
+    // called from semantic3
+    VarDeclaration *declareThis(Scope *sc, AggregateDeclaration *ad);
+    bool equals(RootObject *o);
+
+    int overrides(FuncDeclaration *fd);
+    int findVtblIndex(Dsymbols *vtbl, int dim, bool fix17349 = true);
+    BaseClass *overrideInterface();
+    bool overloadInsert(Dsymbol *s);
+    FuncDeclaration *overloadExactMatch(Type *t);
+    FuncDeclaration *overloadModMatch(Loc loc, Type *tthis, bool &hasOverloads);
+    TemplateDeclaration *findTemplateDeclRoot();
+    bool inUnittest();
+    MATCH leastAsSpecialized(FuncDeclaration *g);
+    LabelDsymbol *searchLabel(Identifier *ident);
+    int getLevel(Loc loc, Scope *sc, FuncDeclaration *fd); // lexical nesting level difference
+    const char *toPrettyChars(bool QualifyTypes = false);
+    const char *toFullSignature();  // for diagnostics, e.g. 'int foo(int x, int y) pure'
+    bool isMain();
+    bool isCMain();
+    bool isWinMain();
+    bool isDllMain();
+    bool isExport();
+    bool isImportedSymbol();
+    bool isCodeseg();
+    bool isOverloadable();
+    PURE isPure();
+    PURE isPureBypassingInference();
+    bool setImpure();
+    bool isSafe();
+    bool isSafeBypassingInference();
+    bool isTrusted();
+    bool setUnsafe();
+
+    bool isNogc();
+    bool isNogcBypassingInference();
+    bool setGC();
+
+    void printGCUsage(Loc loc, const char *warn);
+    bool isolateReturn();
+    bool parametersIntersect(Type *t);
+    virtual bool isNested();
+    AggregateDeclaration *isThis();
+    bool needThis();
+    bool isVirtualMethod();
+    virtual bool isVirtual();
+    virtual bool isFinalFunc();
+    virtual bool addPreInvariant();
+    virtual bool addPostInvariant();
+    const char *kind();
+    FuncDeclaration *isUnique();
+    bool checkNestedReference(Scope *sc, Loc loc);
+    bool needsClosure();
+    bool checkClosure();
+    bool hasNestedFrameRefs();
+    void buildResultVar(Scope *sc, Type *tret);
+    Statement *mergeFrequire(Statement *);
+    Statement *mergeFensure(Statement *, Identifier *oid);
+    Parameters *getParameters(int *pvarargs);
+
+    static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0);
+    static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0);
+    void checkDmain();
+
+    FuncDeclaration *isFuncDeclaration() { return this; }
+
+    virtual FuncDeclaration *toAliasFunc() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
+        Objects *tiargs,
+        Type *tthis,
+        Expressions *arguments,
+        int flags = 0);
+
+class FuncAliasDeclaration : public FuncDeclaration
+{
+public:
+    FuncDeclaration *funcalias;
+    bool hasOverloads;
+
+    FuncAliasDeclaration(Identifier *ident, FuncDeclaration *funcalias, bool hasOverloads = true);
+
+    FuncAliasDeclaration *isFuncAliasDeclaration() { return this; }
+    const char *kind();
+
+    FuncDeclaration *toAliasFunc();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class FuncLiteralDeclaration : public FuncDeclaration
+{
+public:
+    TOK tok;                       // TOKfunction or TOKdelegate
+    Type *treq;                         // target of return type inference
+
+    // backend
+    bool deferToObj;
+
+    FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, TOK tok,
+        ForeachStatement *fes, Identifier *id = NULL);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    bool isNested();
+    AggregateDeclaration *isThis();
+    bool isVirtual();
+    bool addPreInvariant();
+    bool addPostInvariant();
+
+    void modifyReturns(Scope *sc, Type *tret);
+
+    FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; }
+    const char *kind();
+    const char *toPrettyChars(bool QualifyTypes = false);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class CtorDeclaration : public FuncDeclaration
+{
+public:
+    CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    const char *kind();
+    const char *toChars();
+    bool isVirtual();
+    bool addPreInvariant();
+    bool addPostInvariant();
+
+    CtorDeclaration *isCtorDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class PostBlitDeclaration : public FuncDeclaration
+{
+public:
+    PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    bool isVirtual();
+    bool addPreInvariant();
+    bool addPostInvariant();
+    bool overloadInsert(Dsymbol *s);
+
+    PostBlitDeclaration *isPostBlitDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DtorDeclaration : public FuncDeclaration
+{
+public:
+    DtorDeclaration(Loc loc, Loc endloc);
+    DtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    const char *kind();
+    const char *toChars();
+    bool isVirtual();
+    bool addPreInvariant();
+    bool addPostInvariant();
+    bool overloadInsert(Dsymbol *s);
+
+    DtorDeclaration *isDtorDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticCtorDeclaration : public FuncDeclaration
+{
+public:
+    StaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
+    StaticCtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    AggregateDeclaration *isThis();
+    bool isVirtual();
+    bool addPreInvariant();
+    bool addPostInvariant();
+    bool hasStaticCtorOrDtor();
+
+    StaticCtorDeclaration *isStaticCtorDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class SharedStaticCtorDeclaration : public StaticCtorDeclaration
+{
+public:
+    SharedStaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
+    Dsymbol *syntaxCopy(Dsymbol *);
+
+    SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticDtorDeclaration : public FuncDeclaration
+{
+public:
+    VarDeclaration *vgate;      // 'gate' variable
+
+    StaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
+    StaticDtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    AggregateDeclaration *isThis();
+    bool isVirtual();
+    bool hasStaticCtorOrDtor();
+    bool addPreInvariant();
+    bool addPostInvariant();
+
+    StaticDtorDeclaration *isStaticDtorDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class SharedStaticDtorDeclaration : public StaticDtorDeclaration
+{
+public:
+    SharedStaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
+    Dsymbol *syntaxCopy(Dsymbol *);
+
+    SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class InvariantDeclaration : public FuncDeclaration
+{
+public:
+    InvariantDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id = NULL);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    bool isVirtual();
+    bool addPreInvariant();
+    bool addPostInvariant();
+
+    InvariantDeclaration *isInvariantDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class UnitTestDeclaration : public FuncDeclaration
+{
+public:
+    char *codedoc; /** For documented unittest. */
+
+    // toObjFile() these nested functions after this one
+    FuncDeclarations deferredNested;
+
+    UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    AggregateDeclaration *isThis();
+    bool isVirtual();
+    bool addPreInvariant();
+    bool addPostInvariant();
+
+    UnitTestDeclaration *isUnitTestDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class NewDeclaration : public FuncDeclaration
+{
+public:
+    Parameters *parameters;
+    int varargs;
+
+    NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments, int varargs);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    const char *kind();
+    bool isVirtual();
+    bool addPreInvariant();
+    bool addPostInvariant();
+
+    NewDeclaration *isNewDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+
+class DeleteDeclaration : public FuncDeclaration
+{
+public:
+    Parameters *parameters;
+
+    DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    const char *kind();
+    bool isDelete();
+    bool isVirtual();
+    bool addPreInvariant();
+    bool addPostInvariant();
+
+    DeleteDeclaration *isDeleteDeclaration() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#endif /* DMD_DECLARATION_H */
diff --git a/gcc/d/dfrontend/delegatize.c b/gcc/d/dfrontend/delegatize.c
new file mode 100644
index 00000000000..2026c0c9115
--- /dev/null
+++ b/gcc/d/dfrontend/delegatize.c
@@ -0,0 +1,212 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/delegatize.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "expression.h"
+#include "statement.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "init.h"
+#include "tokens.h"
+
+
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+void lambdaSetParent(Expression *e, Scope *sc);
+bool lambdaCheckForNestedRef(Expression *e, Scope *sc);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *initializerToExpression(Initializer *i, Type *t = NULL);
+
+/********************************************
+ * Convert from expression to delegate that returns the expression,
+ * i.e. convert:
+ *      expr
+ * to:
+ *      typeof(expr) delegate() { return expr; }
+ */
+Expression *toDelegate(Expression *e, Type* t, Scope *sc)
+{
+    //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), e->toChars());
+    Loc loc = e->loc;
+
+    TypeFunction *tf = new TypeFunction(NULL, t, 0, LINKd);
+    if (t->hasWild())
+        tf->mod = MODwild;
+    FuncLiteralDeclaration *fld =
+        new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL);
+
+    sc = sc->push();
+    sc->parent = fld;           // set current function to be the delegate
+    lambdaSetParent(e, sc);
+    bool r = lambdaCheckForNestedRef(e, sc);
+    sc = sc->pop();
+
+    if (r)
+        return new ErrorExp();
+
+    Statement *s;
+    if (t->ty == Tvoid)
+        s = new ExpStatement(loc, e);
+    else
+        s = new ReturnStatement(loc, e);
+    fld->fbody = s;
+
+    e = new FuncExp(loc, fld);
+    e = semantic(e, sc);
+    return e;
+}
+
+/******************************************
+ * Patch the parent of declarations to be the new function literal.
+ */
+void lambdaSetParent(Expression *e, Scope *sc)
+{
+    class LambdaSetParent : public StoppableVisitor
+    {
+        Scope *sc;
+    public:
+        LambdaSetParent(Scope *sc) : sc(sc) {}
+
+        void visit(Expression *)
+        {
+        }
+
+        void visit(DeclarationExp *e)
+        {
+            e->declaration->parent = sc->parent;
+        }
+
+        void visit(IndexExp *e)
+        {
+            if (e->lengthVar)
+            {
+                //printf("lengthVar\n");
+                e->lengthVar->parent = sc->parent;
+            }
+        }
+
+        void visit(SliceExp *e)
+        {
+            if (e->lengthVar)
+            {
+                //printf("lengthVar\n");
+                e->lengthVar->parent = sc->parent;
+            }
+        }
+    };
+
+    LambdaSetParent lsp(sc);
+    walkPostorder(e, &lsp);
+}
+
+/*******************************************
+ * Look for references to variables in a scope enclosing the new function literal.
+ * Returns true if error occurs.
+ */
+bool lambdaCheckForNestedRef(Expression *e, Scope *sc)
+{
+    class LambdaCheckForNestedRef : public StoppableVisitor
+    {
+    public:
+        Scope *sc;
+        bool result;
+
+        LambdaCheckForNestedRef(Scope *sc)
+            : sc(sc), result(false)
+        {
+        }
+
+        void visit(Expression *)
+        {
+        }
+
+        void visit(SymOffExp *e)
+        {
+            VarDeclaration *v = e->var->isVarDeclaration();
+            if (v)
+                result = v->checkNestedReference(sc, Loc());
+        }
+
+        void visit(VarExp *e)
+        {
+            VarDeclaration *v = e->var->isVarDeclaration();
+            if (v)
+                result = v->checkNestedReference(sc, Loc());
+        }
+
+        void visit(ThisExp *e)
+        {
+            if (e->var)
+                result = e->var->checkNestedReference(sc, Loc());
+        }
+
+        void visit(DeclarationExp *e)
+        {
+            VarDeclaration *v = e->declaration->isVarDeclaration();
+            if (v)
+            {
+                result = v->checkNestedReference(sc, Loc());
+                if (result)
+                    return;
+
+                /* Some expressions cause the frontend to create a temporary.
+                 * For example, structs with cpctors replace the original
+                 * expression e with:
+                 *  __cpcttmp = __cpcttmp.cpctor(e);
+                 *
+                 * In this instance, we need to ensure that the original
+                 * expression e does not have any nested references by
+                 * checking the declaration initializer too.
+                 */
+                if (v->_init && v->_init->isExpInitializer())
+                {
+                    Expression *ie = initializerToExpression(v->_init);
+                    result = lambdaCheckForNestedRef(ie, sc);
+                }
+            }
+        }
+    };
+
+    LambdaCheckForNestedRef v(sc);
+    walkPostorder(e, &v);
+    return v.result;
+}
+
+bool checkNestedRef(Dsymbol *s, Dsymbol *p)
+{
+    while (s)
+    {
+        if (s == p) // hit!
+            return false;
+
+        if (FuncDeclaration *fd = s->isFuncDeclaration())
+        {
+            if (!fd->isThis() && !fd->isNested())
+                break;
+
+            // Bugzilla 15332: change to delegate if fd is actually nested.
+            if (FuncLiteralDeclaration *fld = fd->isFuncLiteralDeclaration())
+                fld->tok = TOKdelegate;
+        }
+        if (AggregateDeclaration *ad = s->isAggregateDeclaration())
+        {
+            if (ad->storage_class & STCstatic)
+                break;
+        }
+        s = s->toParent2();
+    }
+    return true;
+}
diff --git a/gcc/d/dfrontend/denum.c b/gcc/d/dfrontend/denum.c
new file mode 100644
index 00000000000..1104fc04951
--- /dev/null
+++ b/gcc/d/dfrontend/denum.c
@@ -0,0 +1,726 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/enum.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root.h"
+#include "enum.h"
+#include "mtype.h"
+#include "scope.h"
+#include "id.h"
+#include "expression.h"
+#include "module.h"
+#include "declaration.h"
+#include "init.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+
+/********************************* EnumDeclaration ****************************/
+
+EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
+    : ScopeDsymbol(id)
+{
+    //printf("EnumDeclaration() %s\n", toChars());
+    this->loc = loc;
+    type = new TypeEnum(this);
+    this->memtype = memtype;
+    maxval = NULL;
+    minval = NULL;
+    defaultval = NULL;
+    sinit = NULL;
+    isdeprecated = false;
+    protection = Prot(PROTundefined);
+    parent = NULL;
+    added = false;
+    inuse = 0;
+}
+
+Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    EnumDeclaration *ed = new EnumDeclaration(loc, ident,
+        memtype ? memtype->syntaxCopy() : NULL);
+    return ScopeDsymbol::syntaxCopy(ed);
+}
+
+void EnumDeclaration::setScope(Scope *sc)
+{
+    if (semanticRun > PASSinit)
+        return;
+    ScopeDsymbol::setScope(sc);
+}
+
+void EnumDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+#if 0
+    printf("EnumDeclaration::addMember() %s\n", toChars());
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        EnumMember *em = (*members)[i]->isEnumMember();
+        printf("    member %s\n", em->toChars());
+    }
+#endif
+
+    /* Anonymous enum members get added to enclosing scope.
+     */
+    ScopeDsymbol *scopesym = isAnonymous() ? sds : this;
+
+    if (!isAnonymous())
+    {
+        ScopeDsymbol::addMember(sc, sds);
+
+        if (!symtab)
+            symtab = new DsymbolTable();
+    }
+
+    if (members)
+    {
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            EnumMember *em = (*members)[i]->isEnumMember();
+            em->ed = this;
+            //printf("add %s to scope %s\n", em->toChars(), scopesym->toChars());
+            em->addMember(sc, isAnonymous() ? scopesym : this);
+        }
+    }
+    added = true;
+}
+
+
+void EnumDeclaration::semantic(Scope *sc)
+{
+    //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars());
+    //printf("EnumDeclaration::semantic() %p %s\n", this, toChars());
+    if (semanticRun >= PASSsemanticdone)
+        return;             // semantic() already completed
+    if (semanticRun == PASSsemantic)
+    {
+        assert(memtype);
+        ::error(loc, "circular reference to enum base type %s", memtype->toChars());
+        errors = true;
+        semanticRun = PASSsemanticdone;
+        return;
+    }
+    unsigned dprogress_save = Module::dprogress;
+
+    Scope *scx = NULL;
+    if (_scope)
+    {
+        sc = _scope;
+        scx = _scope;            // save so we don't make redundant copies
+        _scope = NULL;
+    }
+
+    parent = sc->parent;
+    type = type->semantic(loc, sc);
+
+    protection = sc->protection;
+    if (sc->stc & STCdeprecated)
+        isdeprecated = true;
+    userAttribDecl = sc->userAttribDecl;
+
+    semanticRun = PASSsemantic;
+
+    if (!members && !memtype)               // enum ident;
+    {
+        semanticRun = PASSsemanticdone;
+        return;
+    }
+
+    if (!symtab)
+        symtab = new DsymbolTable();
+
+    /* The separate, and distinct, cases are:
+     *  1. enum { ... }
+     *  2. enum : memtype { ... }
+     *  3. enum ident { ... }
+     *  4. enum ident : memtype { ... }
+     *  5. enum ident : memtype;
+     *  6. enum ident;
+     */
+
+    if (memtype)
+    {
+        memtype = memtype->semantic(loc, sc);
+
+        /* Check to see if memtype is forward referenced
+         */
+        if (memtype->ty == Tenum)
+        {
+            EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc);
+            if (!sym->memtype || !sym->members || !sym->symtab || sym->_scope)
+            {
+                // memtype is forward referenced, so try again later
+                _scope = scx ? scx : sc->copy();
+                _scope->setNoFree();
+                _scope->_module->addDeferredSemantic(this);
+                Module::dprogress = dprogress_save;
+                //printf("\tdeferring %s\n", toChars());
+                semanticRun = PASSinit;
+                return;
+            }
+        }
+        if (memtype->ty == Tvoid)
+        {
+            error("base type must not be void");
+            memtype = Type::terror;
+        }
+        if (memtype->ty == Terror)
+        {
+            errors = true;
+            if (members)
+            {
+                for (size_t i = 0; i < members->dim; i++)
+                {
+                    Dsymbol *s = (*members)[i];
+                    s->errors = true;               // poison all the members
+                }
+            }
+            semanticRun = PASSsemanticdone;
+            return;
+        }
+    }
+
+    semanticRun = PASSsemanticdone;
+
+    if (!members)               // enum ident : memtype;
+        return;
+
+    if (members->dim == 0)
+    {
+        error("enum %s must have at least one member", toChars());
+        errors = true;
+        return;
+    }
+
+    Module::dprogress++;
+
+    Scope *sce;
+    if (isAnonymous())
+        sce = sc;
+    else
+    {
+        sce = sc->push(this);
+        sce->parent = this;
+    }
+    sce = sce->startCTFE();
+    sce->setNoFree();                   // needed for getMaxMinValue()
+
+    /* Each enum member gets the sce scope
+     */
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        EnumMember *em = (*members)[i]->isEnumMember();
+        if (em)
+            em->_scope = sce;
+    }
+
+    if (!added)
+    {
+        /* addMember() is not called when the EnumDeclaration appears as a function statement,
+         * so we have to do what addMember() does and install the enum members in the right symbol
+         * table
+         */
+        ScopeDsymbol *scopesym = NULL;
+        if (isAnonymous())
+        {
+            /* Anonymous enum members get added to enclosing scope.
+             */
+            for (Scope *sct = sce; 1; sct = sct->enclosing)
+            {
+                assert(sct);
+                if (sct->scopesym)
+                {
+                    scopesym = sct->scopesym;
+                    if (!sct->scopesym->symtab)
+                        sct->scopesym->symtab = new DsymbolTable();
+                    break;
+                }
+            }
+        }
+        else
+        {
+            // Otherwise enum members are in the EnumDeclaration's symbol table
+            scopesym = this;
+        }
+
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            EnumMember *em = (*members)[i]->isEnumMember();
+            if (em)
+            {
+                em->ed = this;
+                em->addMember(sc, scopesym);
+            }
+        }
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        EnumMember *em = (*members)[i]->isEnumMember();
+        if (em)
+            em->semantic(em->_scope);
+    }
+    //printf("defaultval = %lld\n", defaultval);
+
+    //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars());
+    //printf("members = %s\n", members->toChars());
+}
+
+/******************************
+ * Get the value of the .max/.min property as an Expression
+ * Input:
+ *      id      Id::max or Id::min
+ */
+
+Expression *EnumDeclaration::getMaxMinValue(Loc loc, Identifier *id)
+{
+    //printf("EnumDeclaration::getMaxValue()\n");
+    bool first = true;
+
+    Expression **pval = (id == Id::max) ? &maxval : &minval;
+
+    if (inuse)
+    {
+        error(loc, "recursive definition of .%s property", id->toChars());
+        goto Lerrors;
+    }
+    if (*pval)
+        goto Ldone;
+
+    if (_scope)
+        semantic(_scope);
+    if (errors)
+        goto Lerrors;
+    if (semanticRun == PASSinit || !members)
+    {
+        error("is forward referenced looking for .%s", id->toChars());
+        goto Lerrors;
+    }
+    if (!(memtype && memtype->isintegral()))
+    {
+        error(loc, "has no .%s property because base type %s is not an integral type",
+                id->toChars(),
+                memtype ? memtype->toChars() : "");
+        goto Lerrors;
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        EnumMember *em = (*members)[i]->isEnumMember();
+        if (!em)
+            continue;
+        if (em->errors)
+            goto Lerrors;
+
+        Expression *e = em->value();
+        if (first)
+        {
+            *pval = e;
+            first = false;
+        }
+        else
+        {
+            /* In order to work successfully with UDTs,
+             * build expressions to do the comparisons,
+             * and let the semantic analyzer and constant
+             * folder give us the result.
+             */
+
+            /* Compute:
+             *   if (e > maxval)
+             *      maxval = e;
+             */
+            Expression *ec = new CmpExp(id == Id::max ? TOKgt : TOKlt, em->loc, e, *pval);
+            inuse++;
+            ec = ::semantic(ec, em->_scope);
+            inuse--;
+            ec = ec->ctfeInterpret();
+            if (ec->toInteger())
+                *pval = e;
+        }
+    }
+Ldone:
+  {
+    Expression *e = *pval;
+    if (e->op != TOKerror)
+    {
+        e = e->copy();
+        e->loc = loc;
+    }
+    return e;
+  }
+
+Lerrors:
+    *pval = new ErrorExp();
+    return *pval;
+}
+
+Expression *EnumDeclaration::getDefaultValue(Loc loc)
+{
+    //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars());
+    if (defaultval)
+        return defaultval;
+
+    if (_scope)
+        semantic(_scope);
+    if (errors)
+        goto Lerrors;
+    if (semanticRun == PASSinit || !members)
+    {
+        error(loc, "forward reference of %s.init", toChars());
+        goto Lerrors;
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        EnumMember *em = (*members)[i]->isEnumMember();
+        if (!em)
+            continue;
+        defaultval = em->value();
+        return defaultval;
+    }
+
+Lerrors:
+    defaultval = new ErrorExp();
+    return defaultval;
+}
+
+Type *EnumDeclaration::getMemtype(Loc loc)
+{
+    if (loc.linnum == 0)
+        loc = this->loc;
+    if (_scope)
+    {
+        /* Enum is forward referenced. We don't need to resolve the whole thing,
+         * just the base type
+         */
+        if (memtype)
+            memtype = memtype->semantic(loc, _scope);
+        else
+        {
+            if (!isAnonymous() && members)
+                memtype = Type::tint32;
+        }
+    }
+    if (!memtype)
+    {
+        if (!isAnonymous() && members)
+            memtype = Type::tint32;
+        else
+        {
+            error(loc, "is forward referenced looking for base type");
+            return Type::terror;
+        }
+    }
+    return memtype;
+}
+
+bool EnumDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
+{
+    if (isAnonymous())
+        return Dsymbol::oneMembers(members, ps, ident);
+    return Dsymbol::oneMember(ps, ident);
+}
+
+Type *EnumDeclaration::getType()
+{
+    return type;
+}
+
+const char *EnumDeclaration::kind()
+{
+    return "enum";
+}
+
+bool EnumDeclaration::isDeprecated()
+{
+    return isdeprecated;
+}
+
+Prot EnumDeclaration::prot()
+{
+    return protection;
+}
+
+Dsymbol *EnumDeclaration::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars());
+    if (_scope)
+    {
+        // Try one last time to resolve this enum
+        semantic(_scope);
+    }
+
+    if (!members || !symtab || _scope)
+    {
+        error("is forward referenced when looking for '%s'", ident->toChars());
+        //*(char*)0=0;
+        return NULL;
+    }
+
+    Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
+    return s;
+}
+
+/********************************* EnumMember ****************************/
+
+EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *origType)
+    : VarDeclaration(loc, NULL, id ? id : Id::empty, new ExpInitializer(loc, value))
+{
+    this->ed = NULL;
+    this->origValue = value;
+    this->origType = origType;
+}
+
+Expression *&EnumMember::value()
+{
+    return ((ExpInitializer*)_init)->exp;
+}
+
+Dsymbol *EnumMember::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    return new EnumMember(loc, ident,
+        value() ? value()->syntaxCopy() : NULL,
+        origType ? origType->syntaxCopy() : NULL);
+}
+
+const char *EnumMember::kind()
+{
+    return "enum member";
+}
+
+void EnumMember::semantic(Scope *sc)
+{
+    //printf("EnumMember::semantic() %s\n", toChars());
+    if (errors || semanticRun >= PASSsemanticdone)
+        return;
+    if (semanticRun == PASSsemantic)
+    {
+        error("circular reference to enum member");
+    Lerrors:
+        errors = true;
+        semanticRun = PASSsemanticdone;
+        return;
+    }
+    assert(ed);
+    ed->semantic(sc);
+    if (ed->errors)
+        goto Lerrors;
+
+    if (errors || semanticRun >= PASSsemanticdone)
+        return;
+
+    if (_scope)
+        sc = _scope;
+
+    protection = ed->isAnonymous() ? ed->protection : Prot(PROTpublic);
+    linkage = LINKd;
+    storage_class = STCmanifest;
+    userAttribDecl = ed->isAnonymous() ? ed->userAttribDecl : NULL;
+
+    semanticRun = PASSsemantic;
+
+    // The first enum member is special
+    bool first = (this == (*ed->members)[0]);
+
+    if (origType)
+    {
+        origType = origType->semantic(loc, sc);
+        type = origType;
+        assert(value());          // "type id;" is not a valid enum member declaration
+    }
+
+    if (value())
+    {
+        Expression *e = value();
+        assert(e->dyncast() == DYNCAST_EXPRESSION);
+        e = ::semantic(e, sc);
+        e = resolveProperties(sc, e);
+        e = e->ctfeInterpret();
+        if (e->op == TOKerror)
+            goto Lerrors;
+        if (first && !ed->memtype && !ed->isAnonymous())
+        {
+            ed->memtype = e->type;
+            if (ed->memtype->ty == Terror)
+            {
+                ed->errors = true;
+                goto Lerrors;
+            }
+            if (ed->memtype->ty != Terror)
+            {
+                /* Bugzilla 11746: All of named enum members should have same type
+                 * with the first member. If the following members were referenced
+                 * during the first member semantic, their types should be unified.
+                 */
+                for (size_t i = 0; i < ed->members->dim; i++)
+                {
+                    EnumMember *em = (*ed->members)[i]->isEnumMember();
+                    if (!em || em == this || em->semanticRun < PASSsemanticdone || em->origType)
+                        continue;
+
+                    //printf("[%d] em = %s, em->semanticRun = %d\n", i, toChars(), em->semanticRun);
+                    Expression *ev = em->value();
+                    ev = ev->implicitCastTo(sc, ed->memtype);
+                    ev = ev->ctfeInterpret();
+                    ev = ev->castTo(sc, ed->type);
+                    if (ev->op == TOKerror)
+                        ed->errors = true;
+                    em->value() = ev;
+                }
+                if (ed->errors)
+                {
+                    ed->memtype = Type::terror;
+                    goto Lerrors;
+                }
+            }
+        }
+
+        if (ed->memtype && !origType)
+        {
+            e = e->implicitCastTo(sc, ed->memtype);
+            e = e->ctfeInterpret();
+
+            // save origValue for better json output
+            origValue = e;
+
+            if (!ed->isAnonymous())
+            {
+                e = e->castTo(sc, ed->type);
+                e = e->ctfeInterpret();
+            }
+        }
+        else if (origType)
+        {
+            e = e->implicitCastTo(sc, origType);
+            e = e->ctfeInterpret();
+            assert(ed->isAnonymous());
+
+            // save origValue for better json output
+            origValue = e;
+        }
+        value() = e;
+    }
+    else if (first)
+    {
+        Type *t;
+        if (ed->memtype)
+            t = ed->memtype;
+        else
+        {
+            t = Type::tint32;
+            if (!ed->isAnonymous())
+                ed->memtype = t;
+        }
+        Expression *e = new IntegerExp(loc, 0, Type::tint32);
+        e = e->implicitCastTo(sc, t);
+        e = e->ctfeInterpret();
+
+        // save origValue for better json output
+        origValue = e;
+
+        if (!ed->isAnonymous())
+        {
+            e = e->castTo(sc, ed->type);
+            e = e->ctfeInterpret();
+        }
+        value() = e;
+    }
+    else
+    {
+        /* Find the previous enum member,
+         * and set this to be the previous value + 1
+         */
+        EnumMember *emprev = NULL;
+        for (size_t i = 0; i < ed->members->dim; i++)
+        {
+            EnumMember *em = (*ed->members)[i]->isEnumMember();
+            if (em)
+            {
+                if (em == this)
+                    break;
+                emprev = em;
+            }
+        }
+        assert(emprev);
+        if (emprev->semanticRun < PASSsemanticdone)    // if forward reference
+            emprev->semantic(emprev->_scope);    // resolve it
+        if (emprev->errors)
+            goto Lerrors;
+
+        Expression *eprev = emprev->value();
+        Type *tprev = eprev->type->equals(ed->type) ? ed->memtype : eprev->type;
+
+        Expression *emax = tprev->getProperty(ed->loc, Id::max, 0);
+        emax = ::semantic(emax, sc);
+        emax = emax->ctfeInterpret();
+
+        // Set value to (eprev + 1).
+        // But first check that (eprev != emax)
+        assert(eprev);
+        Expression *e = new EqualExp(TOKequal, loc, eprev, emax);
+        e = ::semantic(e, sc);
+        e = e->ctfeInterpret();
+        if (e->toInteger())
+        {
+            error("initialization with (%s.%s + 1) causes overflow for type '%s'", emprev->ed->toChars(), emprev->toChars(), ed->type->toBasetype()->toChars());
+            goto Lerrors;
+        }
+
+        // Now set e to (eprev + 1)
+        e = new AddExp(loc, eprev, new IntegerExp(loc, 1, Type::tint32));
+        e = ::semantic(e, sc);
+        e = e->castTo(sc, eprev->type);
+        e = e->ctfeInterpret();
+
+        // save origValue (without cast) for better json output
+        if (e->op != TOKerror)  // avoid duplicate diagnostics
+        {
+            assert(emprev->origValue);
+            origValue = new AddExp(loc, emprev->origValue, new IntegerExp(loc, 1, Type::tint32));
+            origValue = ::semantic(origValue, sc);
+            origValue = origValue->ctfeInterpret();
+        }
+
+        if (e->op == TOKerror)
+            goto Lerrors;
+        if (e->type->isfloating())
+        {
+            // Check that e != eprev (not always true for floats)
+            Expression *etest = new EqualExp(TOKequal, loc, e, eprev);
+            etest = ::semantic(etest, sc);
+            etest = etest->ctfeInterpret();
+            if (etest->toInteger())
+            {
+                error("has inexact value, due to loss of precision");
+                goto Lerrors;
+            }
+        }
+        value() = e;
+    }
+    if (!origType)
+        type = value()->type;
+
+    assert(origValue);
+    semanticRun = PASSsemanticdone;
+}
+
+Expression *EnumMember::getVarExp(Loc loc, Scope *sc)
+{
+    semantic(sc);
+    if (errors)
+        return new ErrorExp();
+    Expression *e = new VarExp(loc, this);
+    return ::semantic(e, sc);
+}
diff --git a/gcc/d/dfrontend/dimport.c b/gcc/d/dfrontend/dimport.c
new file mode 100644
index 00000000000..0210ac153b1
--- /dev/null
+++ b/gcc/d/dfrontend/dimport.c
@@ -0,0 +1,501 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/import.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root.h"
+#include "dsymbol.h"
+#include "import.h"
+#include "identifier.h"
+#include "module.h"
+#include "scope.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "id.h"
+#include "attrib.h"
+#include "hdrgen.h"
+
+/********************************* Import ****************************/
+
+Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId,
+        int isstatic)
+    : Dsymbol(NULL)
+{
+    assert(id);
+#if 0
+    printf("Import::Import(");
+    if (packages && packages->dim)
+    {
+        for (size_t i = 0; i < packages->dim; i++)
+        {
+            Identifier *id = (*packages)[i];
+            printf("%s.", id->toChars());
+        }
+    }
+    printf("%s)\n", id->toChars());
+#endif
+    this->loc = loc;
+    this->packages = packages;
+    this->id = id;
+    this->aliasId = aliasId;
+    this->isstatic = isstatic;
+    this->protection = Prot(PROTprivate); // default to private
+    this->pkg = NULL;
+    this->mod = NULL;
+
+    // Set symbol name (bracketed)
+    if (aliasId)
+    {
+        // import [cstdio] = std.stdio;
+        this->ident = aliasId;
+    }
+    else if (packages && packages->dim)
+    {
+        // import [std].stdio;
+        this->ident = (*packages)[0];
+    }
+    else
+    {
+        // import [foo];
+        this->ident = id;
+    }
+}
+
+void Import::addAlias(Identifier *name, Identifier *alias)
+{
+    if (isstatic)
+        error("cannot have an import bind list");
+
+    if (!aliasId)
+        this->ident = NULL;     // make it an anonymous import
+
+    names.push(name);
+    aliases.push(alias);
+}
+
+const char *Import::kind()
+{
+    return isstatic ? (char *)"static import" : (char *)"import";
+}
+
+Prot Import::prot()
+{
+    return protection;
+}
+
+Dsymbol *Import::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+
+    Import *si = new Import(loc, packages, id, aliasId, isstatic);
+
+    for (size_t i = 0; i < names.dim; i++)
+    {
+        si->addAlias(names[i], aliases[i]);
+    }
+
+    return si;
+}
+
+void Import::load(Scope *sc)
+{
+    //printf("Import::load('%s') %p\n", toPrettyChars(), this);
+
+    // See if existing module
+    DsymbolTable *dst = Package::resolve(packages, NULL, &pkg);
+#if 0
+    if (pkg && pkg->isModule())
+    {
+        ::error(loc, "can only import from a module, not from a member of module %s. Did you mean `import %s : %s`?",
+             pkg->toChars(), pkg->toPrettyChars(), id->toChars());
+        mod = pkg->isModule(); // Error recovery - treat as import of that module
+        return;
+    }
+#endif
+    Dsymbol *s = dst->lookup(id);
+    if (s)
+    {
+        if (s->isModule())
+            mod = (Module *)s;
+        else
+        {
+            if (s->isAliasDeclaration())
+            {
+                ::error(loc, "%s %s conflicts with %s", s->kind(), s->toPrettyChars(), id->toChars());
+            }
+            else if (Package *p = s->isPackage())
+            {
+                if (p->isPkgMod == PKGunknown)
+                {
+                    mod = Module::load(loc, packages, id);
+                    if (!mod)
+                        p->isPkgMod = PKGpackage;
+                    else
+                    {
+                        // mod is a package.d, or a normal module which conflicts with the package name.
+                        assert(mod->isPackageFile == (p->isPkgMod == PKGmodule));
+                        if (mod->isPackageFile)
+                            mod->tag = p->tag; // reuse the same package tag
+                    }
+                }
+                else
+                {
+                    mod = p->isPackageMod();
+                }
+                if (!mod)
+                {
+                    ::error(loc, "can only import from a module, not from package %s.%s",
+                        p->toPrettyChars(), id->toChars());
+                }
+            }
+            else if (pkg)
+            {
+                ::error(loc, "can only import from a module, not from package %s.%s",
+                    pkg->toPrettyChars(), id->toChars());
+            }
+            else
+            {
+                ::error(loc, "can only import from a module, not from package %s",
+                    id->toChars());
+            }
+        }
+    }
+
+    if (!mod)
+    {
+        // Load module
+        mod = Module::load(loc, packages, id);
+        if (mod)
+        {
+            dst->insert(id, mod);           // id may be different from mod->ident,
+                                            // if so then insert alias
+        }
+    }
+    if (mod && !mod->importedFrom)
+        mod->importedFrom = sc ? sc->_module->importedFrom : Module::rootModule;
+    if (!pkg)
+        pkg = mod;
+
+    //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
+}
+
+void Import::importAll(Scope *sc)
+{
+    if (!mod)
+    {
+        load(sc);
+        if (mod)                // if successfully loaded module
+        {
+            if (mod->md && mod->md->isdeprecated)
+            {
+                Expression *msg = mod->md->msg;
+                if (StringExp *se = msg ? msg->toStringExp() : NULL)
+                    mod->deprecation(loc, "is deprecated - %s", se->string);
+                else
+                    mod->deprecation(loc, "is deprecated");
+            }
+
+            mod->importAll(NULL);
+
+            if (sc->explicitProtection)
+                protection = sc->protection;
+            if (!isstatic && !aliasId && !names.dim)
+            {
+                sc->scopesym->importScope(mod, protection);
+            }
+        }
+    }
+}
+
+void Import::semantic(Scope *sc)
+{
+    //printf("Import::semantic('%s') %s\n", toPrettyChars(), id->toChars());
+
+    if (_scope)
+    {
+        sc = _scope;
+        _scope = NULL;
+    }
+
+    // Load if not already done so
+    if (!mod)
+    {
+        load(sc);
+        if (mod)
+            mod->importAll(NULL);
+    }
+
+    if (mod)
+    {
+        // Modules need a list of each imported module
+        //printf("%s imports %s\n", sc->_module->toChars(), mod->toChars());
+        sc->_module->aimports.push(mod);
+
+        if (sc->explicitProtection)
+            protection = sc->protection;
+
+        if (!aliasId && !names.dim) // neither a selective nor a renamed import
+        {
+            ScopeDsymbol *scopesym = NULL;
+            if (sc->explicitProtection)
+                protection = sc->protection.kind;
+            for (Scope *scd = sc; scd; scd = scd->enclosing)
+            {
+                if (!scd->scopesym)
+                    continue;
+                scopesym = scd->scopesym;
+                break;
+            }
+
+            if (!isstatic)
+            {
+                scopesym->importScope(mod, protection);
+            }
+
+            // Mark the imported packages as accessible from the current
+            // scope. This access check is necessary when using FQN b/c
+            // we're using a single global package tree. See Bugzilla 313.
+            if (packages)
+            {
+                // import a.b.c.d;
+                Package *p = pkg; // a
+                scopesym->addAccessiblePackage(p, protection);
+                for (size_t i = 1; i < packages->dim; i++) // [b, c]
+                {
+                    Identifier *id = (*packages)[i];
+                    p = (Package *) p->symtab->lookup(id);
+                    scopesym->addAccessiblePackage(p, protection);
+                }
+            }
+            scopesym->addAccessiblePackage(mod, protection); // d
+        }
+
+        mod->semantic(NULL);
+
+        if (mod->needmoduleinfo)
+        {
+            //printf("module4 %s because of %s\n", sc->_module->toChars(), mod->toChars());
+            sc->_module->needmoduleinfo = 1;
+        }
+
+        sc = sc->push(mod);
+        sc->protection = protection;
+        for (size_t i = 0; i < aliasdecls.dim; i++)
+        {
+            AliasDeclaration *ad = aliasdecls[i];
+            //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i]->toChars(), names[i]->toChars(), ad->_scope);
+            if (mod->search(loc, names[i]))
+            {
+                ad->semantic(sc);
+                // If the import declaration is in non-root module,
+                // analysis of the aliased symbol is deferred.
+                // Therefore, don't see the ad->aliassym or ad->type here.
+            }
+            else
+            {
+                Dsymbol *s = mod->search_correct(names[i]);
+                if (s)
+                    mod->error(loc, "import '%s' not found, did you mean %s '%s'?", names[i]->toChars(), s->kind(), s->toChars());
+                else
+                    mod->error(loc, "import '%s' not found", names[i]->toChars());
+                ad->type = Type::terror;
+            }
+        }
+        sc = sc->pop();
+    }
+
+    // object self-imports itself, so skip that (Bugzilla 7547)
+    // don't list pseudo modules __entrypoint.d, __main.d (Bugzilla 11117, 11164)
+    if (global.params.moduleDeps != NULL &&
+        !(id == Id::object && sc->_module->ident == Id::object) &&
+        sc->_module->ident != Id::entrypoint &&
+        strcmp(sc->_module->ident->toChars(), "__main") != 0)
+    {
+        /* The grammar of the file is:
+         *      ImportDeclaration
+         *          ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
+         *      ModuleAliasIdentifier ] "\n"
+         *
+         *      BasicImportDeclaration
+         *          ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string"
+         *              " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
+         *
+         *      FilePath
+         *          - any string with '(', ')' and '\' escaped with the '\' character
+         */
+
+        OutBuffer *ob = global.params.moduleDeps;
+        Module* imod = sc->instantiatingModule();
+        if (!global.params.moduleDepsFile)
+            ob->writestring("depsImport ");
+        ob->writestring(imod->toPrettyChars());
+        ob->writestring(" (");
+        escapePath(ob,  imod->srcfile->toChars());
+        ob->writestring(") : ");
+
+        // use protection instead of sc->protection because it couldn't be
+        // resolved yet, see the comment above
+        protectionToBuffer(ob, protection);
+        ob->writeByte(' ');
+        if (isstatic)
+        {
+            stcToBuffer(ob, STCstatic);
+            ob->writeByte(' ');
+        }
+        ob->writestring(": ");
+
+        if (packages)
+        {
+            for (size_t i = 0; i < packages->dim; i++)
+            {
+                Identifier *pid = (*packages)[i];
+                ob->printf("%s.", pid->toChars());
+            }
+        }
+
+        ob->writestring(id->toChars());
+        ob->writestring(" (");
+        if (mod)
+            escapePath(ob, mod->srcfile->toChars());
+        else
+            ob->writestring("???");
+        ob->writeByte(')');
+
+        for (size_t i = 0; i < names.dim; i++)
+        {
+            if (i == 0)
+                ob->writeByte(':');
+            else
+                ob->writeByte(',');
+
+            Identifier *name = names[i];
+            Identifier *alias = aliases[i];
+
+            if (!alias)
+            {
+                ob->printf("%s", name->toChars());
+                alias = name;
+            }
+            else
+                ob->printf("%s=%s", alias->toChars(), name->toChars());
+        }
+
+        if (aliasId)
+                ob->printf(" -> %s", aliasId->toChars());
+
+        ob->writenl();
+    }
+
+    //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg);
+}
+
+void Import::semantic2(Scope *sc)
+{
+    //printf("Import::semantic2('%s')\n", toChars());
+    if (mod)
+    {
+        mod->semantic2(NULL);
+        if (mod->needmoduleinfo)
+        {
+            //printf("module5 %s because of %s\n", sc->_module->toChars(), mod->toChars());
+            if (sc)
+                sc->_module->needmoduleinfo = 1;
+        }
+    }
+}
+
+Dsymbol *Import::toAlias()
+{
+    if (aliasId)
+        return mod;
+    return this;
+}
+
+/*****************************
+ * Add import to sd's symbol table.
+ */
+
+void Import::addMember(Scope *sc, ScopeDsymbol *sd)
+{
+    //printf("Import::addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd->toChars(), sc);
+    if (names.dim == 0)
+        return Dsymbol::addMember(sc, sd);
+
+    if (aliasId)
+        Dsymbol::addMember(sc, sd);
+
+    /* Instead of adding the import to sd's symbol table,
+     * add each of the alias=name pairs
+     */
+    for (size_t i = 0; i < names.dim; i++)
+    {
+        Identifier *name = names[i];
+        Identifier *alias = aliases[i];
+
+        if (!alias)
+            alias = name;
+
+        TypeIdentifier *tname = new TypeIdentifier(loc, name);
+        AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname);
+        ad->_import = this;
+        ad->addMember(sc, sd);
+
+        aliasdecls.push(ad);
+    }
+}
+
+void Import::setScope(Scope *sc)
+{
+    Dsymbol::setScope(sc);
+    if (aliasdecls.dim)
+    {
+        if (!mod)
+            importAll(sc);
+
+        sc = sc->push(mod);
+        sc->protection = protection;
+        for (size_t i = 0; i < aliasdecls.dim; i++)
+        {
+            AliasDeclaration *ad = aliasdecls[i];
+            ad->setScope(sc);
+        }
+        sc = sc->pop();
+    }
+}
+
+Dsymbol *Import::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
+
+    if (!pkg)
+    {
+        load(NULL);
+        mod->importAll(NULL);
+        mod->semantic(NULL);
+    }
+
+    // Forward it to the package/module
+    return pkg->search(loc, ident, flags);
+}
+
+bool Import::overloadInsert(Dsymbol *s)
+{
+    /* Allow multiple imports with the same package base, but disallow
+     * alias collisions (Bugzilla 5412).
+     */
+    assert(ident && ident == s->ident);
+    Import *imp;
+    if (!aliasId && (imp = s->isImport()) != NULL && !imp->aliasId)
+        return true;
+    else
+        return false;
+}
diff --git a/gcc/d/dfrontend/dinterpret.c b/gcc/d/dfrontend/dinterpret.c
new file mode 100644
index 00000000000..7917ab8b1c2
--- /dev/null
+++ b/gcc/d/dfrontend/dinterpret.c
@@ -0,0 +1,7009 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/interpret.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>                     // mem{cpy|set}()
+
+#include "rmem.h"
+
+#include "statement.h"
+#include "expression.h"
+#include "cond.h"
+#include "init.h"
+#include "staticassert.h"
+#include "mtype.h"
+#include "scope.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+#include "utf.h"
+#include "attrib.h" // for AttribDeclaration
+
+#include "template.h"
+#include "ctfe.h"
+
+/* Interpreter: what form of return value expression is required?
+ */
+enum CtfeGoal
+{
+    ctfeNeedRvalue,   // Must return an Rvalue (== CTFE value)
+    ctfeNeedLvalue,   // Must return an Lvalue (== CTFE reference)
+    ctfeNeedNothing   // The return value is not required
+};
+
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+Expression *interpret(Statement *s, InterState *istate);
+Expression *interpret(Expression *e, InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *initializerToExpression(Initializer *i, Type *t = NULL);
+Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
+
+#define LOG     0
+#define LOGASSIGN 0
+#define LOGCOMPILE 0
+#define SHOWPERFORMANCE 0
+
+// Maximum allowable recursive function calls in CTFE
+#define CTFE_RECURSION_LIMIT 1000
+
+/**
+  The values of all CTFE variables
+*/
+struct CtfeStack
+{
+private:
+    /* The stack. Every declaration we encounter is pushed here,
+       together with the VarDeclaration, and the previous
+       stack address of that variable, so that we can restore it
+       when we leave the stack frame.
+       Note that when a function is forward referenced, the interpreter must
+       run semantic3, and that may start CTFE again with a NULL istate. Thus
+       the stack might not be empty when CTFE begins.
+
+       Ctfe Stack addresses are just 0-based integers, but we save
+       them as 'void *' because Array can only do pointers.
+    */
+    Expressions values;   // values on the stack
+    VarDeclarations vars; // corresponding variables
+    Array<void *> savedId; // id of the previous state of that var
+
+    Array<void *> frames;  // all previous frame pointers
+    Expressions savedThis;   // all previous values of localThis
+
+    /* Global constants get saved here after evaluation, so we never
+     * have to redo them. This saves a lot of time and memory.
+     */
+    Expressions globalValues; // values of global constants
+
+    size_t framepointer;      // current frame pointer
+    size_t maxStackPointer;   // most stack we've ever used
+    Expression *localThis;    // value of 'this', or NULL if none
+public:
+    CtfeStack();
+
+    size_t stackPointer();
+
+    // The current value of 'this', or NULL if none
+    Expression *getThis();
+
+    // Largest number of stack positions we've used
+    size_t maxStackUsage();
+    // Start a new stack frame, using the provided 'this'.
+    void startFrame(Expression *thisexp);
+    void endFrame();
+    bool isInCurrentFrame(VarDeclaration *v);
+    Expression *getValue(VarDeclaration *v);
+    void setValue(VarDeclaration *v, Expression *e);
+    void push(VarDeclaration *v);
+    void pop(VarDeclaration *v);
+    void popAll(size_t stackpointer);
+    void saveGlobalConstant(VarDeclaration *v, Expression *e);
+};
+
+struct InterState
+{
+    InterState *caller;         // calling function's InterState
+    FuncDeclaration *fd;        // function being interpreted
+    Statement *start;           // if !=NULL, start execution at this statement
+    /* target of CTFEExp result; also
+     * target of labelled CTFEExp or
+     * CTFEExp. (NULL if no label).
+     */
+    Statement *gotoTarget;
+
+    InterState();
+};
+
+/************** CtfeStack ********************************************/
+
+CtfeStack ctfeStack;
+
+CtfeStack::CtfeStack() : framepointer(0), maxStackPointer(0)
+{
+}
+
+size_t CtfeStack::stackPointer()
+{
+    return values.dim;
+}
+
+Expression *CtfeStack::getThis()
+{
+    return localThis;
+}
+
+// Largest number of stack positions we've used
+size_t CtfeStack::maxStackUsage()
+{
+    return maxStackPointer;
+}
+
+void CtfeStack::startFrame(Expression *thisexp)
+{
+    frames.push((void *)(size_t)(framepointer));
+    savedThis.push(localThis);
+    framepointer = stackPointer();
+    localThis = thisexp;
+}
+
+void CtfeStack::endFrame()
+{
+    size_t oldframe = (size_t)(frames[frames.dim-1]);
+    localThis = savedThis[savedThis.dim-1];
+    popAll(framepointer);
+    framepointer = oldframe;
+    frames.setDim(frames.dim - 1);
+    savedThis.setDim(savedThis.dim -1);
+}
+
+bool CtfeStack::isInCurrentFrame(VarDeclaration *v)
+{
+    if (v->isDataseg() && !v->isCTFE())
+        return false;   // It's a global
+    return v->ctfeAdrOnStack >= framepointer;
+}
+
+Expression *CtfeStack::getValue(VarDeclaration *v)
+{
+    if ((v->isDataseg() || v->storage_class & STCmanifest) && !v->isCTFE())
+    {
+        assert(v->ctfeAdrOnStack >= 0 &&
+        v->ctfeAdrOnStack < globalValues.dim);
+        return globalValues[v->ctfeAdrOnStack];
+    }
+    assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer());
+    return values[v->ctfeAdrOnStack];
+}
+
+void CtfeStack::setValue(VarDeclaration *v, Expression *e)
+{
+    assert(!v->isDataseg() || v->isCTFE());
+    assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer());
+    values[v->ctfeAdrOnStack] = e;
+}
+
+void CtfeStack::push(VarDeclaration *v)
+{
+    assert(!v->isDataseg() || v->isCTFE());
+    if (v->ctfeAdrOnStack != (size_t)-1 &&
+        v->ctfeAdrOnStack >= framepointer)
+    {
+        // Already exists in this frame, reuse it.
+        values[v->ctfeAdrOnStack] = NULL;
+        return;
+    }
+    savedId.push((void *)(size_t)(v->ctfeAdrOnStack));
+    v->ctfeAdrOnStack = (int)values.dim;
+    vars.push(v);
+    values.push(NULL);
+}
+
+void CtfeStack::pop(VarDeclaration *v)
+{
+    assert(!v->isDataseg() || v->isCTFE());
+    assert(!(v->storage_class & (STCref | STCout)));
+    int oldid = v->ctfeAdrOnStack;
+    v->ctfeAdrOnStack = (int)(size_t)(savedId[oldid]);
+    if (v->ctfeAdrOnStack == values.dim - 1)
+    {
+        values.pop();
+        vars.pop();
+        savedId.pop();
+    }
+}
+
+void CtfeStack::popAll(size_t stackpointer)
+{
+    if (stackPointer() > maxStackPointer)
+        maxStackPointer = stackPointer();
+    assert(values.dim >= stackpointer);
+    for (size_t i = stackpointer; i < values.dim; ++i)
+    {
+        VarDeclaration *v = vars[i];
+        v->ctfeAdrOnStack = (int)(size_t)(savedId[i]);
+    }
+    values.setDim(stackpointer);
+    vars.setDim(stackpointer);
+    savedId.setDim(stackpointer);
+}
+
+void CtfeStack::saveGlobalConstant(VarDeclaration *v, Expression *e)
+{
+     assert(v->_init && (v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) && !v->isCTFE());
+     v->ctfeAdrOnStack = (int)globalValues.dim;
+     globalValues.push(e);
+}
+
+/************** InterState  ********************************************/
+
+InterState::InterState()
+{
+    memset(this, 0, sizeof(InterState));
+}
+
+/************** CtfeStatus ********************************************/
+
+int CtfeStatus::callDepth = 0;
+int CtfeStatus::stackTraceCallsToSuppress = 0;
+int CtfeStatus::maxCallDepth = 0;
+int CtfeStatus::numArrayAllocs = 0;
+int CtfeStatus::numAssignments = 0;
+
+// CTFE diagnostic information
+void printCtfePerformanceStats()
+{
+#if SHOWPERFORMANCE
+    printf("        ---- CTFE Performance ----\n");
+    printf("max call depth = %d\tmax stack = %d\n", CtfeStatus::maxCallDepth, ctfeStack.maxStackUsage());
+    printf("array allocs = %d\tassignments = %d\n\n", CtfeStatus::numArrayAllocs, CtfeStatus::numAssignments);
+#endif
+}
+
+VarDeclaration *findParentVar(Expression *e);
+Expression *evaluateIfBuiltin(InterState *istate, Loc loc,
+    FuncDeclaration *fd, Expressions *arguments, Expression *pthis);
+Expression *evaluatePostblit(InterState *istate, Expression *e);
+Expression *evaluateDtor(InterState *istate, Expression *e);
+Expression *scrubReturnValue(Loc loc, Expression *e);
+
+Expression *scrubCacheValue(Loc loc, Expression *e);
+
+
+/*************************************
+ * CTFE-object code for a single function
+ *
+ * Currently only counts the number of local variables in the function
+ */
+struct CompiledCtfeFunction
+{
+    FuncDeclaration *func; // Function being compiled, NULL if global scope
+    int numVars;           // Number of variables declared in this function
+    Loc callingloc;
+
+    CompiledCtfeFunction(FuncDeclaration *f)
+    {
+        func = f;
+        numVars = 0;
+    }
+
+    void onDeclaration(VarDeclaration *v)
+    {
+        //printf("%s CTFE declare %s\n", v->loc.toChars(), v->toChars());
+        ++numVars;
+    }
+
+    void onExpression(Expression *e)
+    {
+        class VarWalker : public StoppableVisitor
+        {
+        public:
+            CompiledCtfeFunction *ccf;
+
+            VarWalker(CompiledCtfeFunction *ccf)
+                : ccf(ccf)
+            {
+            }
+
+            void visit(Expression *e)
+            {
+            }
+
+            void visit(ErrorExp *e)
+            {
+                // Currently there's a front-end bug: silent errors
+                // can occur inside delegate literals inside is(typeof()).
+                // Suppress the check in this case.
+                if (global.gag && ccf->func)
+                {
+                    stop = 1;
+                    return;
+                }
+
+                ::error(e->loc, "CTFE internal error: ErrorExp in %s\n", ccf->func ? ccf->func->loc.toChars() : ccf->callingloc.toChars());
+                assert(0);
+            }
+
+            void visit(DeclarationExp *e)
+            {
+                VarDeclaration *v = e->declaration->isVarDeclaration();
+                if (!v)
+                    return;
+                TupleDeclaration *td = v->toAlias()->isTupleDeclaration();
+                if (td)
+                {
+                    if (!td->objects)
+                        return;
+                    for (size_t i= 0; i < td->objects->dim; ++i)
+                    {
+                        RootObject *o = td->objects->tdata()[i];
+                        Expression *ex = isExpression(o);
+                        DsymbolExp *s = (ex && ex->op == TOKdsymbol) ? (DsymbolExp *)ex : NULL;
+                        assert(s);
+                        VarDeclaration *v2 = s->s->isVarDeclaration();
+                        assert(v2);
+                        if (!v2->isDataseg() || v2->isCTFE())
+                            ccf->onDeclaration(v2);
+                    }
+                }
+                else if (!(v->isDataseg() || v->storage_class & STCmanifest) || v->isCTFE())
+                    ccf->onDeclaration(v);
+                Dsymbol *s = v->toAlias();
+                if (s == v && !v->isStatic() && v->_init)
+                {
+                    ExpInitializer *ie = v->_init->isExpInitializer();
+                    if (ie)
+                        ccf->onExpression(ie->exp);
+                }
+            }
+
+            void visit(IndexExp *e)
+            {
+                if (e->lengthVar)
+                    ccf->onDeclaration(e->lengthVar);
+            }
+
+            void visit(SliceExp *e)
+            {
+                if (e->lengthVar)
+                    ccf->onDeclaration(e->lengthVar);
+            }
+        };
+
+        VarWalker v(this);
+        walkPostorder(e, &v);
+    }
+};
+
+class CtfeCompiler : public Visitor
+{
+public:
+    CompiledCtfeFunction *ccf;
+
+    CtfeCompiler(CompiledCtfeFunction *ccf)
+        : ccf(ccf)
+    {
+    }
+
+    void visit(Statement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s Statement::ctfeCompile %s\n", s->loc.toChars(), s->toChars());
+    #endif
+        assert(0);
+    }
+
+    void visit(ExpStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s ExpStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        if (s->exp)
+            ccf->onExpression(s->exp);
+    }
+
+    void visit(CompoundStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s CompoundStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        for (size_t i = 0; i < s->statements->dim; i++)
+        {
+            Statement *sx = (*s->statements)[i];
+            if (sx)
+                ctfeCompile(sx);
+        }
+    }
+
+    void visit(UnrolledLoopStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s UnrolledLoopStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        for (size_t i = 0; i < s->statements->dim; i++)
+        {
+            Statement *sx = (*s->statements)[i];
+            if (sx)
+                ctfeCompile(sx);
+        }
+    }
+
+    void visit(IfStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s IfStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+
+        ccf->onExpression(s->condition);
+        if (s->ifbody)
+            ctfeCompile(s->ifbody);
+        if (s->elsebody)
+            ctfeCompile(s->elsebody);
+    }
+
+    void visit(ScopeStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s ScopeStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        if (s->statement)
+            ctfeCompile(s->statement);
+    }
+
+    void visit(OnScopeStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s OnScopeStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        // rewritten to try/catch/finally
+        assert(0);
+    }
+
+    void visit(DoStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s DoStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        ccf->onExpression(s->condition);
+        if (s->_body)
+            ctfeCompile(s->_body);
+    }
+
+    void visit(WhileStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s WhileStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        // rewritten to ForStatement
+        assert(0);
+    }
+
+    void visit(ForStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s ForStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+
+        if (s->_init)
+            ctfeCompile(s->_init);
+        if (s->condition)
+            ccf->onExpression(s->condition);
+        if (s->increment)
+            ccf->onExpression(s->increment);
+        if (s->_body)
+            ctfeCompile(s->_body);
+    }
+
+    void visit(ForeachStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s ForeachStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        // rewritten for ForStatement
+        assert(0);
+    }
+
+    void visit(SwitchStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s SwitchStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        ccf->onExpression(s->condition);
+        // Note that the body contains the the Case and Default
+        // statements, so we only need to compile the expressions
+        for (size_t i = 0; i < s->cases->dim; i++)
+        {
+            ccf->onExpression((*s->cases)[i]->exp);
+        }
+        if (s->_body)
+            ctfeCompile(s->_body);
+    }
+
+    void visit(CaseStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s CaseStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        if (s->statement)
+            ctfeCompile(s->statement);
+    }
+
+    void visit(DefaultStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s DefaultStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        if (s->statement)
+            ctfeCompile(s->statement);
+    }
+
+    void visit(GotoDefaultStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s GotoDefaultStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+    }
+
+    void visit(GotoCaseStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s GotoCaseStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+    }
+
+    void visit(SwitchErrorStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s SwitchErrorStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+    }
+
+    void visit(ReturnStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s ReturnStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        if (s->exp)
+            ccf->onExpression(s->exp);
+    }
+
+    void visit(BreakStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s BreakStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+    }
+
+    void visit(ContinueStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s ContinueStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+    }
+
+    void visit(WithStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s WithStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        // If it is with(Enum) {...}, just execute the body.
+        if (s->exp->op == TOKscope || s->exp->op == TOKtype)
+        {
+        }
+        else
+        {
+            ccf->onDeclaration(s->wthis);
+            ccf->onExpression(s->exp);
+        }
+        if (s->_body)
+            ctfeCompile(s->_body);
+    }
+
+    void visit(TryCatchStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s TryCatchStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        if (s->_body)
+            ctfeCompile(s->_body);
+        for (size_t i = 0; i < s->catches->dim; i++)
+        {
+            Catch *ca = (*s->catches)[i];
+            if (ca->var)
+                ccf->onDeclaration(ca->var);
+            if (ca->handler)
+                ctfeCompile(ca->handler);
+        }
+    }
+
+    void visit(TryFinallyStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s TryFinallyStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        if (s->_body)
+            ctfeCompile(s->_body);
+        if (s->finalbody)
+            ctfeCompile(s->finalbody);
+    }
+
+    void visit(ThrowStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s ThrowStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        ccf->onExpression(s->exp);
+    }
+
+    void visit(GotoStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s GotoStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+    }
+
+    void visit(LabelStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s LabelStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        if (s->statement)
+            ctfeCompile(s->statement);
+    }
+
+    void visit(ImportStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s ImportStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        // Contains no variables or executable code
+    }
+
+    void visit(ForeachRangeStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s ForeachRangeStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        // rewritten for ForStatement
+        assert(0);
+    }
+
+    void visit(AsmStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s AsmStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        // we can't compile asm statements
+    }
+
+#ifdef IN_GCC
+    void visit(ExtAsmStatement *s)
+    {
+    #if LOGCOMPILE
+        printf("%s ExtAsmStatement::ctfeCompile\n", s->loc.toChars());
+    #endif
+        // we can't compile ext asm statements
+    }
+#endif
+
+    void ctfeCompile(Statement *s)
+    {
+        s->accept(this);
+    }
+};
+
+/*************************************
+ * Compile this function for CTFE.
+ * At present, this merely allocates variables.
+ */
+void ctfeCompile(FuncDeclaration *fd)
+{
+#if LOGCOMPILE
+    printf("\n%s FuncDeclaration::ctfeCompile %s\n", fd->loc.toChars(), fd->toChars());
+#endif
+    assert(!fd->ctfeCode);
+    assert(!fd->semantic3Errors);
+    assert(fd->semanticRun == PASSsemantic3done);
+
+    fd->ctfeCode = new CompiledCtfeFunction(fd);
+    if (fd->parameters)
+    {
+        Type *tb = fd->type->toBasetype();
+        assert(tb->ty == Tfunction);
+        for (size_t i = 0; i < fd->parameters->dim; i++)
+        {
+            VarDeclaration *v = (*fd->parameters)[i];
+            fd->ctfeCode->onDeclaration(v);
+        }
+    }
+    if (fd->vresult)
+        fd->ctfeCode->onDeclaration(fd->vresult);
+    CtfeCompiler v(fd->ctfeCode);
+    v.ctfeCompile(fd->fbody);
+}
+
+/*************************************
+ * Entry point for CTFE.
+ * A compile-time result is required. Give an error if not possible.
+ *
+ * `e` must be semantically valid expression. In other words, it should not
+ * contain any `ErrorExp`s in it. But, CTFE interpretation will cross over
+ * functions and may invoke a function that contains `ErrorStatement` in its body.
+ * If that, the "CTFE failed because of previous errors" error is raised.
+ */
+Expression *ctfeInterpret(Expression *e)
+{
+    if (e->op == TOKerror)
+        return e;
+    assert(e->type);                    // Bugzilla 14642
+    //assert(e->type->ty != Terror);    // FIXME
+    if (e->type->ty == Terror)
+        return new ErrorExp();
+
+    // This code is outside a function, but still needs to be compiled
+    // (there are compiler-generated temporary variables such as __dollar).
+    // However, this will only be run once and can then be discarded.
+    CompiledCtfeFunction ctfeCodeGlobal(NULL);
+    ctfeCodeGlobal.callingloc = e->loc;
+    ctfeCodeGlobal.onExpression(e);
+
+    Expression *result = interpret(e, NULL);
+    if (!CTFEExp::isCantExp(result))
+        result = scrubReturnValue(e->loc, result);
+    if (CTFEExp::isCantExp(result))
+        result = new ErrorExp();
+    return result;
+}
+
+/* Run CTFE on the expression, but allow the expression to be a TypeExp
+ *  or a tuple containing a TypeExp. (This is required by pragma(msg)).
+ */
+Expression *ctfeInterpretForPragmaMsg(Expression *e)
+{
+    if (e->op == TOKerror || e->op == TOKtype)
+        return e;
+
+    // It's also OK for it to be a function declaration (happens only with
+    // __traits(getOverloads))
+    if (e->op == TOKvar && ((VarExp *)e)->var->isFuncDeclaration())
+    {
+        return e;
+    }
+
+    if (e->op != TOKtuple)
+        return e->ctfeInterpret();
+
+    // Tuples need to be treated seperately, since they are
+    // allowed to contain a TypeExp in this case.
+
+    TupleExp *tup = (TupleExp *)e;
+    Expressions *expsx = NULL;
+    for (size_t i = 0; i < tup->exps->dim; ++i)
+    {
+        Expression *g = (*tup->exps)[i];
+        Expression *h = g;
+        h = ctfeInterpretForPragmaMsg(g);
+        if (h != g)
+        {
+            if (!expsx)
+            {
+                expsx = new Expressions();
+                expsx->setDim(tup->exps->dim);
+                for (size_t j = 0; j < tup->exps->dim; j++)
+                    (*expsx)[j] = (*tup->exps)[j];
+            }
+            (*expsx)[i] = h;
+        }
+    }
+    if (expsx)
+    {
+        TupleExp *te = new TupleExp(e->loc, expsx);
+        expandTuples(te->exps);
+        te->type = new TypeTuple(te->exps);
+        return te;
+    }
+    return e;
+}
+
+/*************************************
+ * Attempt to interpret a function given the arguments.
+ * Input:
+ *      istate     state for calling function (NULL if none)
+ *      arguments  function arguments
+ *      thisarg    'this', if a needThis() function, NULL if not.
+ *
+ * Return result expression if successful, TOKcantexp if not,
+ * or CTFEExp if function returned void.
+ */
+
+Expression *interpret(FuncDeclaration *fd, InterState *istate, Expressions *arguments, Expression *thisarg)
+{
+#if LOG
+    printf("\n********\n%s FuncDeclaration::interpret(istate = %p) %s\n", fd->loc.toChars(), istate, fd->toChars());
+#endif
+    if (fd->semanticRun == PASSsemantic3)
+    {
+        fd->error("circular dependency. Functions cannot be interpreted while being compiled");
+        return CTFEExp::cantexp;
+    }
+    if (!fd->functionSemantic3())
+        return CTFEExp::cantexp;
+    if (fd->semanticRun < PASSsemantic3done)
+        return CTFEExp::cantexp;
+
+    // CTFE-compile the function
+    if (!fd->ctfeCode)
+        ctfeCompile(fd);
+
+    Type *tb = fd->type->toBasetype();
+    assert(tb->ty == Tfunction);
+    TypeFunction *tf = (TypeFunction *)tb;
+    if (tf->varargs && arguments &&
+        ((fd->parameters && arguments->dim != fd->parameters->dim) || (!fd->parameters && arguments->dim)))
+    {
+        fd->error("C-style variadic functions are not yet implemented in CTFE");
+        return CTFEExp::cantexp;
+    }
+
+    // Nested functions always inherit the 'this' pointer from the parent,
+    // except for delegates. (Note that the 'this' pointer may be null).
+    // Func literals report isNested() even if they are in global scope,
+    // so we need to check that the parent is a function.
+    if (fd->isNested() && fd->toParent2()->isFuncDeclaration() && !thisarg && istate)
+        thisarg = ctfeStack.getThis();
+
+    if (fd->needThis() && !thisarg)
+    {
+        // error, no this. Prevent segfault.
+        // Here should be unreachable by the strict 'this' check in front-end.
+        fd->error("need 'this' to access member %s", fd->toChars());
+        return CTFEExp::cantexp;
+    }
+
+    // Place to hold all the arguments to the function while
+    // we are evaluating them.
+    Expressions eargs;
+    size_t dim = arguments ? arguments->dim : 0;
+    assert((fd->parameters ? fd->parameters->dim : 0) == dim);
+
+    /* Evaluate all the arguments to the function,
+     * store the results in eargs[]
+     */
+    eargs.setDim(dim);
+    for (size_t i = 0; i < dim; i++)
+    {
+        Expression *earg = (*arguments)[i];
+        Parameter *fparam = Parameter::getNth(tf->parameters, i);
+
+        if (fparam->storageClass & (STCout | STCref))
+        {
+            if (!istate && (fparam->storageClass & STCout))
+            {
+                // initializing an out parameter involves writing to it.
+                earg->error("global %s cannot be passed as an 'out' parameter at compile time", earg->toChars());
+                return CTFEExp::cantexp;
+            }
+            // Convert all reference arguments into lvalue references
+            earg = interpret(earg, istate, ctfeNeedLvalue);
+            if (CTFEExp::isCantExp(earg))
+                return earg;
+        }
+        else if (fparam->storageClass & STClazy)
+        {
+        }
+        else
+        {
+            /* Value parameters
+             */
+            Type *ta = fparam->type->toBasetype();
+            if (ta->ty == Tsarray && earg->op == TOKaddress)
+            {
+                /* Static arrays are passed by a simple pointer.
+                 * Skip past this to get at the actual arg.
+                 */
+                earg = ((AddrExp *)earg)->e1;
+            }
+            earg = interpret(earg, istate);
+            if (CTFEExp::isCantExp(earg))
+                return earg;
+            /* Struct literals are passed by value, but we don't need to
+             * copy them if they are passed as const
+             */
+            if (earg->op == TOKstructliteral && !(fparam->storageClass & (STCconst | STCimmutable)))
+                earg = copyLiteral(earg).copy();
+        }
+        if (earg->op == TOKthrownexception)
+        {
+            if (istate)
+                return earg;
+            ((ThrownExceptionExp *)earg)->generateUncaughtError();
+            return CTFEExp::cantexp;
+        }
+        eargs[i] = earg;
+    }
+
+    // Now that we've evaluated all the arguments, we can start the frame
+    // (this is the moment when the 'call' actually takes place).
+    InterState istatex;
+    istatex.caller = istate;
+    istatex.fd = fd;
+    ctfeStack.startFrame(thisarg);
+    if (fd->vthis && thisarg)
+    {
+        ctfeStack.push(fd->vthis);
+        setValue(fd->vthis, thisarg);
+    }
+
+    for (size_t i = 0; i < dim; i++)
+    {
+        Expression *earg = eargs[i];
+        Parameter *fparam = Parameter::getNth(tf->parameters, i);
+        VarDeclaration *v = (*fd->parameters)[i];
+#if LOG
+        printf("arg[%d] = %s\n", i, earg->toChars());
+#endif
+        ctfeStack.push(v);
+
+        if ((fparam->storageClass & (STCout | STCref)) &&
+            earg->op == TOKvar && ((VarExp *)earg)->var->toParent2() == fd)
+        {
+            VarDeclaration *vx = ((VarExp *)earg)->var->isVarDeclaration();
+            if (!vx)
+            {
+                fd->error("cannot interpret %s as a ref parameter", earg->toChars());
+                return CTFEExp::cantexp;
+            }
+
+            /* vx is a variable that is declared in fd.
+             * It means that fd is recursively called. e.g.
+             *
+             *  void fd(int n, ref int v = dummy) {
+             *      int vx;
+             *      if (n == 1) fd(2, vx);
+             *  }
+             *  fd(1);
+             *
+             * The old value of vx on the stack in fd(1)
+             * should be saved at the start of fd(2, vx) call.
+             */
+            int oldadr = vx->ctfeAdrOnStack;
+
+            ctfeStack.push(vx);
+            assert(!hasValue(vx));  // vx is made uninitialized
+
+            // Bugzilla 14299: v->ctfeAdrOnStack should be saved already
+            // in the stack before the overwrite.
+            v->ctfeAdrOnStack = oldadr;
+            assert(hasValue(v));    // ref parameter v should refer existing value.
+        }
+        else
+        {
+            // Value parameters and non-trivial references
+            setValueWithoutChecking(v, earg);
+        }
+#if LOG || LOGASSIGN
+        printf("interpreted arg[%d] = %s\n", i, earg->toChars());
+        showCtfeExpr(earg);
+#endif
+    }
+
+    if (fd->vresult)
+        ctfeStack.push(fd->vresult);
+
+    // Enter the function
+    ++CtfeStatus::callDepth;
+    if (CtfeStatus::callDepth > CtfeStatus::maxCallDepth)
+        CtfeStatus::maxCallDepth = CtfeStatus::callDepth;
+
+    Expression *e = NULL;
+    while (1)
+    {
+        if (CtfeStatus::callDepth > CTFE_RECURSION_LIMIT)
+        {
+            // This is a compiler error. It must not be suppressed.
+            global.gag = 0;
+            fd->error("CTFE recursion limit exceeded");
+            e = CTFEExp::cantexp;
+            break;
+        }
+        e = interpret(fd->fbody, &istatex);
+        if (CTFEExp::isCantExp(e))
+        {
+#if LOG
+            printf("function body failed to interpret\n");
+#endif
+        }
+
+        if (istatex.start)
+        {
+            fd->error("CTFE internal error: failed to resume at statement %s", istatex.start->toChars());
+            return CTFEExp::cantexp;
+        }
+
+        /* This is how we deal with a recursive statement AST
+         * that has arbitrary goto statements in it.
+         * Bubble up a 'result' which is the target of the goto
+         * statement, then go recursively down the AST looking
+         * for that statement, then execute starting there.
+         */
+        if (CTFEExp::isGotoExp(e))
+        {
+            istatex.start = istatex.gotoTarget; // set starting statement
+            istatex.gotoTarget = NULL;
+        }
+        else
+        {
+            assert(!e || (e->op != TOKcontinue && e->op != TOKbreak));
+            break;
+        }
+    }
+    // If fell off the end of a void function, return void
+    if (!e && tf->next->ty == Tvoid)
+        e = CTFEExp::voidexp;
+    if (tf->isref && e->op == TOKvar && ((VarExp *)e)->var == fd->vthis)
+        e = thisarg;
+    assert(e != NULL);
+
+    // Leave the function
+    --CtfeStatus::callDepth;
+
+    ctfeStack.endFrame();
+
+    // If it generated an uncaught exception, report error.
+    if (!istate && e->op == TOKthrownexception)
+    {
+        ((ThrownExceptionExp *)e)->generateUncaughtError();
+        e = CTFEExp::cantexp;
+    }
+
+    return e;
+}
+
+class Interpreter : public Visitor
+{
+public:
+    InterState *istate;
+    CtfeGoal goal;
+
+    Expression *result;
+
+    Interpreter(InterState *istate, CtfeGoal goal)
+        : istate(istate), goal(goal)
+    {
+        result = NULL;
+    }
+
+    // If e is TOKthrowexception or TOKcantexp,
+    // set it to 'result' and returns true.
+    bool exceptionOrCant(Expression *e)
+    {
+        if (exceptionOrCantInterpret(e))
+        {
+            result = e;
+            return true;
+        }
+        return false;
+    }
+
+    /******************************** Statement ***************************/
+
+    void visit(Statement *s)
+    {
+    #if LOG
+        printf("%s Statement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start)
+        {
+            if (istate->start != s)
+                return;
+            istate->start = NULL;
+        }
+
+        s->error("statement %s cannot be interpreted at compile time", s->toChars());
+        result = CTFEExp::cantexp;
+    }
+
+    void visit(ExpStatement *s)
+    {
+    #if LOG
+        printf("%s ExpStatement::interpret(%s)\n", s->loc.toChars(), s->exp ? s->exp->toChars() : "");
+    #endif
+        if (istate->start)
+        {
+            if (istate->start != s)
+                return;
+            istate->start = NULL;
+        }
+
+        Expression *e = interpret(s->exp, istate, ctfeNeedNothing);
+        if (exceptionOrCant(e))
+            return;
+    }
+
+    void visit(CompoundStatement *s)
+    {
+    #if LOG
+        printf("%s CompoundStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+
+        size_t dim = s->statements ? s->statements->dim : 0;
+        for (size_t i = 0; i < dim; i++)
+        {
+            Statement *sx = (*s->statements)[i];
+            result = interpret(sx, istate);
+            if (result)
+                break;
+        }
+    #if LOG
+        printf("%s -CompoundStatement::interpret() %p\n", s->loc.toChars(), result);
+    #endif
+    }
+
+    void visit(UnrolledLoopStatement *s)
+    {
+    #if LOG
+        printf("%s UnrolledLoopStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+
+        size_t dim = s->statements ? s->statements->dim : 0;
+        for (size_t i = 0; i < dim; i++)
+        {
+            Statement *sx = (*s->statements)[i];
+            Expression *e = interpret(sx, istate);
+            if (!e)                 // suceeds to interpret, or goto target
+                continue;           // was not fonnd when istate->start != NULL
+            if (exceptionOrCant(e))
+                return;
+            if (e->op == TOKbreak)
+            {
+                if (istate->gotoTarget && istate->gotoTarget != s)
+                {
+                    result = e;     // break at a higher level
+                    return;
+                }
+                istate->gotoTarget = NULL;
+                result = NULL;
+                return;
+            }
+            if (e->op == TOKcontinue)
+            {
+                if (istate->gotoTarget && istate->gotoTarget != s)
+                {
+                    result = e;     // continue at a higher level
+                    return;
+                }
+                istate->gotoTarget = NULL;
+                continue;
+            }
+
+            // expression from return statement, or thrown exception
+            result = e;
+            break;
+        }
+    }
+
+    void visit(IfStatement *s)
+    {
+    #if LOG
+        printf("%s IfStatement::interpret(%s)\n", s->loc.toChars(), s->condition->toChars());
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+        if (istate->start)
+        {
+            Expression *e = NULL;
+            e = interpret(s->ifbody, istate);
+            if (!e && istate->start)
+                e = interpret(s->elsebody, istate);
+            result = e;
+            return;
+        }
+
+        Expression *e = interpret(s->condition, istate);
+        assert(e);
+        if (exceptionOrCant(e))
+            return;
+
+        if (isTrueBool(e))
+            result = interpret(s->ifbody, istate);
+        else if (e->isBool(false))
+            result = interpret(s->elsebody, istate);
+        else
+        {
+            // no error, or assert(0)?
+            result = CTFEExp::cantexp;
+        }
+    }
+
+    void visit(ScopeStatement *s)
+    {
+    #if LOG
+        printf("%s ScopeStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+
+        result = interpret(s->statement, istate);
+    }
+
+    /**
+      Given an expression e which is about to be returned from the current
+      function, generate an error if it contains pointers to local variables.
+      Return true if it is safe to return, false if an error was generated.
+
+      Only checks expressions passed by value (pointers to local variables
+      may already be stored in members of classes, arrays, or AAs which
+      were passed as mutable function parameters).
+    */
+
+    static bool stopPointersEscaping(Loc loc, Expression *e)
+    {
+        if (!e->type->hasPointers())
+            return true;
+        if (isPointer(e->type))
+        {
+            Expression *x = e;
+            if (e->op == TOKaddress)
+                x = ((AddrExp *)e)->e1;
+            VarDeclaration *v;
+            while (x->op == TOKvar &&
+                (v = ((VarExp *)x)->var->isVarDeclaration()) != NULL)
+            {
+                if (v->storage_class & STCref)
+                {
+                    x = getValue(v);
+                    if (e->op == TOKaddress)
+                        ((AddrExp *)e)->e1 = x;
+                    continue;
+                }
+                if (ctfeStack.isInCurrentFrame(v))
+                {
+                    error(loc, "returning a pointer to a local stack variable");
+                    return false;
+                }
+                else
+                    break;
+            }
+            // TODO: If it is a TOKdotvar or TOKindex, we should check that it is not
+            // pointing to a local struct or static array.
+        }
+        if (e->op == TOKstructliteral)
+        {
+            StructLiteralExp *se = (StructLiteralExp *)e;
+            return stopPointersEscapingFromArray(loc, se->elements);
+        }
+        if (e->op == TOKarrayliteral)
+        {
+            return stopPointersEscapingFromArray(loc, ((ArrayLiteralExp *)e)->elements);
+        }
+        if (e->op == TOKassocarrayliteral)
+        {
+            AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
+            if (!stopPointersEscapingFromArray(loc, aae->keys))
+                return false;
+            return stopPointersEscapingFromArray(loc, aae->values);
+        }
+        return true;
+    }
+
+    // Check all members of an array for escaping local variables. Return false if error
+    static bool stopPointersEscapingFromArray(Loc loc, Expressions *elems)
+    {
+        for (size_t i = 0; i < elems->dim; i++)
+        {
+            Expression *m = (*elems)[i];
+            if (!m)
+                continue;
+            if (!stopPointersEscaping(loc, m))
+                return false;
+        }
+        return true;
+    }
+
+    void visit(ReturnStatement *s)
+    {
+    #if LOG
+        printf("%s ReturnStatement::interpret(%s)\n", s->loc.toChars(), s->exp ? s->exp->toChars() : "");
+    #endif
+        if (istate->start)
+        {
+            if (istate->start != s)
+                return;
+            istate->start = NULL;
+        }
+
+        if (!s->exp)
+        {
+            result = CTFEExp::voidexp;
+            return;
+        }
+
+        assert(istate && istate->fd && istate->fd->type && istate->fd->type->ty == Tfunction);
+        TypeFunction *tf = (TypeFunction *)istate->fd->type;
+
+        /* If the function returns a ref AND it's been called from an assignment,
+         * we need to return an lvalue. Otherwise, just do an (rvalue) interpret.
+         */
+        if (tf->isref)
+        {
+            result = interpret(s->exp, istate, ctfeNeedLvalue);
+            return;
+        }
+        if (tf->next && tf->next->ty == Tdelegate && istate->fd->closureVars.dim > 0)
+        {
+            // To support this, we need to copy all the closure vars
+            // into the delegate literal.
+            s->error("closures are not yet supported in CTFE");
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        // We need to treat pointers specially, because TOKsymoff can be used to
+        // return a value OR a pointer
+        Expression *e = interpret(s->exp, istate);
+        if (exceptionOrCant(e))
+            return;
+
+        // Disallow returning pointers to stack-allocated variables (bug 7876)
+        if (!stopPointersEscaping(s->loc, e))
+        {
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        if (needToCopyLiteral(e))
+            e = copyLiteral(e).copy();
+    #if LOGASSIGN
+        printf("RETURN %s\n", s->loc.toChars());
+        showCtfeExpr(e);
+    #endif
+        result = e;
+    }
+
+    static Statement *findGotoTarget(InterState *istate, Identifier *ident)
+    {
+        Statement *target = NULL;
+        if (ident)
+        {
+            LabelDsymbol *label = istate->fd->searchLabel(ident);
+            assert(label && label->statement);
+            LabelStatement *ls = label->statement;
+            target = ls->gotoTarget ? ls->gotoTarget : ls->statement;
+        }
+        return target;
+    }
+
+    void visit(BreakStatement *s)
+    {
+    #if LOG
+        printf("%s BreakStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start)
+        {
+            if (istate->start != s)
+                return;
+            istate->start = NULL;
+        }
+
+        istate->gotoTarget = findGotoTarget(istate, s->ident);
+        result = CTFEExp::breakexp;
+    }
+
+    void visit(ContinueStatement *s)
+    {
+    #if LOG
+        printf("%s ContinueStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start)
+        {
+            if (istate->start != s)
+                return;
+            istate->start = NULL;
+        }
+
+        istate->gotoTarget = findGotoTarget(istate, s->ident);
+        result = CTFEExp::continueexp;
+    }
+
+    void visit(WhileStatement *s)
+    {
+    #if LOG
+        printf("WhileStatement::interpret()\n");
+    #endif
+        assert(0);                  // rewritten to ForStatement
+    }
+
+    void visit(DoStatement *s)
+    {
+    #if LOG
+        printf("%s DoStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+
+        while (1)
+        {
+            Expression *e = interpret(s->_body, istate);
+            if (!e && istate->start)    // goto target was not found
+                return;
+            assert(!istate->start);
+
+            if (exceptionOrCant(e))
+                return;
+            if (e && e->op == TOKbreak)
+            {
+                if (istate->gotoTarget && istate->gotoTarget != s)
+                {
+                    result = e;     // break at a higher level
+                    return;
+                }
+                istate->gotoTarget = NULL;
+                break;
+            }
+            if (e && e->op == TOKcontinue)
+            {
+                if (istate->gotoTarget && istate->gotoTarget != s)
+                {
+                    result = e;     // continue at a higher level
+                    return;
+                }
+                istate->gotoTarget = NULL;
+                e = NULL;
+            }
+            if (e)
+            {
+                result = e; // bubbled up from ReturnStatement
+                return;
+            }
+
+            e = interpret(s->condition, istate);
+            if (exceptionOrCant(e))
+                return;
+            if (!e->isConst())
+            {
+                result = CTFEExp::cantexp;
+                return;
+            }
+            if (e->isBool(false))
+                break;
+            assert(isTrueBool(e));
+        }
+        assert(result == NULL);
+    }
+
+    void visit(ForStatement *s)
+    {
+    #if LOG
+        printf("%s ForStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+
+        Expression *ei = interpret(s->_init, istate);
+        if (exceptionOrCant(ei))
+            return;
+        assert(!ei); // s->init never returns from function, or jumps out from it
+
+        while (1)
+        {
+            if (s->condition && !istate->start)
+            {
+                Expression *e = interpret(s->condition, istate);
+                if (exceptionOrCant(e))
+                    return;
+                if (e->isBool(false))
+                    break;
+                assert(isTrueBool(e));
+            }
+
+            Expression *e = interpret(s->_body, istate);
+            if (!e && istate->start)    // goto target was not found
+                return;
+            assert(!istate->start);
+
+            if (exceptionOrCant(e))
+                return;
+            if (e && e->op == TOKbreak)
+            {
+                if (istate->gotoTarget && istate->gotoTarget != s)
+                {
+                    result = e;     // break at a higher level
+                    return;
+                }
+                istate->gotoTarget = NULL;
+                break;
+            }
+            if (e && e->op == TOKcontinue)
+            {
+                if (istate->gotoTarget && istate->gotoTarget != s)
+                {
+                    result = e;     // continue at a higher level
+                    return;
+                }
+                istate->gotoTarget = NULL;
+                e = NULL;
+            }
+            if (e)
+            {
+                result = e; // bubbled up from ReturnStatement
+                return;
+            }
+
+            e = interpret(s->increment, istate, ctfeNeedNothing);
+            if (exceptionOrCant(e))
+                return;
+        }
+        assert(result == NULL);
+    }
+
+    void visit(ForeachStatement *s)
+    {
+        assert(0);                  // rewritten to ForStatement
+    }
+
+    void visit(ForeachRangeStatement *s)
+    {
+        assert(0);                  // rewritten to ForStatement
+    }
+
+    void visit(SwitchStatement *s)
+    {
+    #if LOG
+        printf("%s SwitchStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+        if (istate->start)
+        {
+            Expression *e = interpret(s->_body, istate);
+            if (istate->start)      // goto target was not found
+                return;
+            if (exceptionOrCant(e))
+                return;
+            if (e && e->op == TOKbreak)
+            {
+                if (istate->gotoTarget && istate->gotoTarget != s)
+                {
+                    result = e;     // break at a higher level
+                    return;
+                }
+                istate->gotoTarget = NULL;
+                e = NULL;
+            }
+            result = e;
+            return;
+        }
+
+        Expression *econdition = interpret(s->condition, istate);
+        if (exceptionOrCant(econdition))
+            return;
+
+        Statement *scase = NULL;
+        size_t dim = s->cases ? s->cases->dim : 0;
+        for (size_t i = 0; i < dim; i++)
+        {
+            CaseStatement *cs = (*s->cases)[i];
+            Expression *ecase = interpret(cs->exp, istate);
+            if (exceptionOrCant(ecase))
+                return;
+            if (ctfeEqual(cs->exp->loc, TOKequal, econdition, ecase))
+            {
+                scase = cs;
+                break;
+            }
+        }
+        if (!scase)
+        {
+            if (s->hasNoDefault)
+                s->error("no default or case for %s in switch statement", econdition->toChars());
+            scase = s->sdefault;
+        }
+
+        assert(scase);
+
+        /* Jump to scase
+         */
+        istate->start = scase;
+        Expression *e = interpret(s->_body, istate);
+        assert(!istate->start); // jump must not fail
+        if (e && e->op == TOKbreak)
+        {
+            if (istate->gotoTarget && istate->gotoTarget != s)
+            {
+                result = e;     // break at a higher level
+                return;
+            }
+            istate->gotoTarget = NULL;
+            e = NULL;
+        }
+        result = e;
+    }
+
+    void visit(CaseStatement *s)
+    {
+    #if LOG
+        printf("%s CaseStatement::interpret(%s) this = %p\n", s->loc.toChars(), s->exp->toChars(), s);
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+
+        result = interpret(s->statement, istate);
+    }
+
+    void visit(DefaultStatement *s)
+    {
+    #if LOG
+        printf("%s DefaultStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+
+        result = interpret(s->statement, istate);
+    }
+
+    void visit(GotoStatement *s)
+    {
+    #if LOG
+        printf("%s GotoStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start)
+        {
+            if (istate->start != s)
+                return;
+            istate->start = NULL;
+        }
+
+        assert(s->label && s->label->statement);
+        istate->gotoTarget = s->label->statement;
+        result = CTFEExp::gotoexp;
+    }
+
+    void visit(GotoCaseStatement *s)
+    {
+    #if LOG
+        printf("%s GotoCaseStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start)
+        {
+            if (istate->start != s)
+                return;
+            istate->start = NULL;
+        }
+
+        assert(s->cs);
+        istate->gotoTarget = s->cs;
+        result = CTFEExp::gotoexp;
+    }
+
+    void visit(GotoDefaultStatement *s)
+    {
+    #if LOG
+        printf("%s GotoDefaultStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start)
+        {
+            if (istate->start != s)
+                return;
+            istate->start = NULL;
+        }
+
+        assert(s->sw && s->sw->sdefault);
+        istate->gotoTarget = s->sw->sdefault;
+        result = CTFEExp::gotoexp;
+    }
+
+    void visit(LabelStatement *s)
+    {
+    #if LOG
+        printf("%s LabelStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+
+        result = interpret(s->statement, istate);
+    }
+
+    void visit(TryCatchStatement *s)
+    {
+    #if LOG
+        printf("%s TryCatchStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+        if (istate->start)
+        {
+            Expression *e = NULL;
+            e = interpret(s->_body, istate);
+            for (size_t i = 0; i < s->catches->dim; i++)
+            {
+                if (e || !istate->start)    // goto target was found
+                    break;
+                Catch *ca = (*s->catches)[i];
+                e = interpret(ca->handler, istate);
+            }
+            result = e;
+            return;
+        }
+
+        Expression *e = interpret(s->_body, istate);
+
+        // An exception was thrown
+        if (e && e->op == TOKthrownexception)
+        {
+            ThrownExceptionExp *ex = (ThrownExceptionExp *)e;
+            Type *extype = ex->thrown->originalClass()->type;
+
+            // Search for an appropriate catch clause.
+            for (size_t i = 0; i < s->catches->dim; i++)
+            {
+                Catch *ca = (*s->catches)[i];
+                Type *catype = ca->type;
+                if (!catype->equals(extype) && !catype->isBaseOf(extype, NULL))
+                    continue;
+
+                // Execute the handler
+                if (ca->var)
+                {
+                    ctfeStack.push(ca->var);
+                    setValue(ca->var, ex->thrown);
+                }
+                e = interpret(ca->handler, istate);
+                if (CTFEExp::isGotoExp(e))
+                {
+                    /* This is an optimization that relies on the locality of the jump target.
+                     * If the label is in the same catch handler, the following scan
+                     * would find it quickly and can reduce jump cost.
+                     * Otherwise, the catch block may be unnnecessary scanned again
+                     * so it would make CTFE speed slower.
+                     */
+                    InterState istatex = *istate;
+                    istatex.start = istate->gotoTarget; // set starting statement
+                    istatex.gotoTarget = NULL;
+                    Expression *eh = interpret(ca->handler, &istatex);
+                    if (!istatex.start)
+                    {
+                        istate->gotoTarget = NULL;
+                        e = eh;
+                    }
+                }
+                break;
+            }
+        }
+        result = e;
+    }
+
+    static bool isAnErrorException(ClassDeclaration *cd)
+    {
+        return cd == ClassDeclaration::errorException || ClassDeclaration::errorException->isBaseOf(cd, NULL);
+    }
+
+    static ThrownExceptionExp *chainExceptions(ThrownExceptionExp *oldest, ThrownExceptionExp *newest)
+    {
+    #if LOG
+        printf("Collided exceptions %s %s\n", oldest->thrown->toChars(), newest->thrown->toChars());
+    #endif
+        // Little sanity check to make sure it's really a Throwable
+        ClassReferenceExp *boss = oldest->thrown;
+        assert((*boss->value->elements)[4]->type->ty == Tclass);    // Throwable.next
+        ClassReferenceExp *collateral = newest->thrown;
+        if ( isAnErrorException(collateral->originalClass()) &&
+            !isAnErrorException(boss->originalClass()))
+        {
+            // The new exception bypass the existing chain
+            assert((*collateral->value->elements)[5]->type->ty == Tclass);
+            (*collateral->value->elements)[5] = boss;
+            return newest;
+        }
+        while ((*boss->value->elements)[4]->op == TOKclassreference)
+        {
+            boss = (ClassReferenceExp *)(*boss->value->elements)[4];
+        }
+        (*boss->value->elements)[4] = collateral;
+        return oldest;
+    }
+
+    void visit(TryFinallyStatement *s)
+    {
+    #if LOG
+        printf("%s TryFinallyStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+        if (istate->start)
+        {
+            Expression *e = NULL;
+            e = interpret(s->_body, istate);
+            // Jump into/out from finalbody is disabled in semantic analysis.
+            // and jump inside will be handled by the ScopeStatement == finalbody.
+            result = e;
+            return;
+        }
+
+        Expression *ex = interpret(s->_body, istate);
+        if (CTFEExp::isCantExp(ex))
+        {
+            result = ex;
+            return;
+        }
+        while (CTFEExp::isGotoExp(ex))
+        {
+            // If the goto target is within the body, we must not interpret the finally statement,
+            // because that will call destructors for objects within the scope, which we should not do.
+            InterState istatex = *istate;
+            istatex.start = istate->gotoTarget; // set starting statement
+            istatex.gotoTarget = NULL;
+            Expression *bex = interpret(s->_body, &istatex);
+            if (istatex.start)
+            {
+              // The goto target is outside the current scope.
+              break;
+            }
+            // The goto target was within the body.
+            if (CTFEExp::isCantExp(bex))
+            {
+                result = bex;
+                return;
+            }
+            *istate = istatex;
+            ex = bex;
+        }
+        Expression *ey = interpret(s->finalbody, istate);
+        if (CTFEExp::isCantExp(ey))
+        {
+            result = ey;
+            return;
+        }
+        if (ey && ey->op == TOKthrownexception)
+        {
+            // Check for collided exceptions
+            if (ex && ex->op == TOKthrownexception)
+                ex = chainExceptions((ThrownExceptionExp *)ex, (ThrownExceptionExp *)ey);
+            else
+                ex = ey;
+        }
+        result = ex;
+    }
+
+    void visit(ThrowStatement *s)
+    {
+    #if LOG
+        printf("%s ThrowStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start)
+        {
+            if (istate->start != s)
+                return;
+            istate->start = NULL;
+        }
+
+        Expression *e = interpret(s->exp, istate);
+        if (exceptionOrCant(e))
+            return;
+
+        assert(e->op == TOKclassreference);
+        result = new ThrownExceptionExp(s->loc, (ClassReferenceExp *)e);
+    }
+
+    void visit(OnScopeStatement *s)
+    {
+        assert(0);
+    }
+
+    void visit(WithStatement *s)
+    {
+    #if LOG
+        printf("%s WithStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start == s)
+            istate->start = NULL;
+        if (istate->start)
+        {
+            result = s->_body ? interpret(s->_body, istate) : NULL;
+            return;
+        }
+
+        // If it is with(Enum) {...}, just execute the body.
+        if (s->exp->op == TOKscope || s->exp->op == TOKtype)
+        {
+            result = interpret(s->_body, istate);
+            return;
+        }
+
+        Expression *e = interpret(s->exp, istate);
+        if (exceptionOrCant(e))
+            return;
+
+        if (s->wthis->type->ty == Tpointer && s->exp->type->ty != Tpointer)
+        {
+            e = new AddrExp(s->loc, e);
+            e->type = s->wthis->type;
+        }
+        ctfeStack.push(s->wthis);
+        setValue(s->wthis, e);
+        e = interpret(s->_body, istate);
+        if (CTFEExp::isGotoExp(e))
+        {
+            /* This is an optimization that relies on the locality of the jump target.
+             * If the label is in the same WithStatement, the following scan
+             * would find it quickly and can reduce jump cost.
+             * Otherwise, the statement body may be unnnecessary scanned again
+             * so it would make CTFE speed slower.
+             */
+            InterState istatex = *istate;
+            istatex.start = istate->gotoTarget; // set starting statement
+            istatex.gotoTarget = NULL;
+            Expression *ex = interpret(s->_body, &istatex);
+            if (!istatex.start)
+            {
+                istate->gotoTarget = NULL;
+                e = ex;
+            }
+        }
+        ctfeStack.pop(s->wthis);
+        result = e;
+    }
+
+    void visit(AsmStatement *s)
+    {
+    #if LOG
+        printf("%s AsmStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start)
+        {
+            if (istate->start != s)
+                return;
+            istate->start = NULL;
+        }
+
+        s->error("asm statements cannot be interpreted at compile time");
+        result = CTFEExp::cantexp;
+    }
+
+#ifdef IN_GCC
+    void visit(ExtAsmStatement *s)
+    {
+    #if LOG
+        printf("%s ExtAsmStatement::interpret()\n", s->loc.toChars());
+    #endif
+        if (istate->start)
+        {
+            if (istate->start != s)
+                return;
+            istate->start = NULL;
+        }
+
+        s->error("extended asm statements cannot be interpreted at compile time");
+        result = CTFEExp::cantexp;
+    }
+#endif
+
+    void visit(ImportStatement *s)
+    {
+    #if LOG
+        printf("ImportStatement::interpret()\n");
+    #endif
+        if (istate->start)
+        {
+            if (istate->start != s)
+                return;
+            istate->start = NULL;
+        }
+    }
+
+    /******************************** Expression ***************************/
+
+    void visit(Expression *e)
+    {
+    #if LOG
+        printf("%s Expression::interpret() '%s' %s\n", e->loc.toChars(), Token::toChars(e->op), e->toChars());
+        printf("type = %s\n", e->type->toChars());
+        e->print();
+    #endif
+        e->error("cannot interpret %s at compile time", e->toChars());
+        result = CTFEExp::cantexp;
+    }
+
+    void visit(ThisExp *e)
+    {
+    #if LOG
+        printf("%s ThisExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        if (goal == ctfeNeedLvalue)
+        {
+            if (istate->fd->vthis)
+            {
+                result = new VarExp(e->loc, istate->fd->vthis);
+                result->type = e->type;
+            }
+            else
+                result = e;
+            return;
+        }
+
+        result = ctfeStack.getThis();
+        if (result)
+        {
+            assert(result->op == TOKstructliteral ||
+                   result->op == TOKclassreference);
+            return;
+        }
+        e->error("value of 'this' is not known at compile time");
+        result = CTFEExp::cantexp;
+    }
+
+    void visit(NullExp *e)
+    {
+        result = e;
+    }
+
+    void visit(IntegerExp *e)
+    {
+    #if LOG
+        printf("%s IntegerExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        result = e;
+    }
+
+    void visit(RealExp *e)
+    {
+    #if LOG
+        printf("%s RealExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        result = e;
+    }
+
+    void visit(ComplexExp *e)
+    {
+        result = e;
+    }
+
+    void visit(StringExp *e)
+    {
+    #if LOG
+        printf("%s StringExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        /* Attempts to modify string literals are prevented
+         * in BinExp::interpretAssignCommon.
+         */
+        result = e;
+    }
+
+    void visit(FuncExp *e)
+    {
+    #if LOG
+        printf("%s FuncExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        result = e;
+    }
+
+    void visit(SymOffExp *e)
+    {
+    #if LOG
+        printf("%s SymOffExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        if (e->var->isFuncDeclaration() && e->offset == 0)
+        {
+            result = e;
+            return;
+        }
+        if (isTypeInfo_Class(e->type) && e->offset == 0)
+        {
+            result = e;
+            return;
+        }
+        if (e->type->ty != Tpointer)
+        {
+            // Probably impossible
+            e->error("cannot interpret %s at compile time", e->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        Type *pointee = ((TypePointer *)e->type)->next;
+        if (e->var->isThreadlocal())
+        {
+            e->error("cannot take address of thread-local variable %s at compile time", e->var->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        // Check for taking an address of a shared variable.
+        // If the shared variable is an array, the offset might not be zero.
+        Type *fromType = NULL;
+        if (e->var->type->ty == Tarray || e->var->type->ty == Tsarray)
+        {
+            fromType = ((TypeArray *)(e->var->type))->next;
+        }
+        if (e->var->isDataseg() &&
+            ((e->offset == 0 && isSafePointerCast(e->var->type, pointee)) ||
+             (fromType && isSafePointerCast(fromType, pointee))))
+        {
+            result = e;
+            return;
+        }
+        Expression *val = getVarExp(e->loc, istate, e->var, goal);
+        if (exceptionOrCant(val))
+            return;
+        if (val->type->ty == Tarray || val->type->ty == Tsarray)
+        {
+            // Check for unsupported type painting operations
+            Type *elemtype = ((TypeArray *)(val->type))->next;
+            d_uns64 elemsize = elemtype->size();
+
+            // It's OK to cast from fixed length to dynamic array, eg &int[3] to int[]*
+            if (val->type->ty == Tsarray && pointee->ty == Tarray &&
+                elemsize == pointee->nextOf()->size())
+            {
+                result = new AddrExp(e->loc, val);
+                result->type = e->type;
+                return;
+            }
+
+            // It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*.
+            if (val->type->ty == Tsarray && pointee->ty == Tsarray &&
+                elemsize == pointee->nextOf()->size())
+            {
+                size_t d = (size_t)((TypeSArray *)pointee)->dim->toInteger();
+                Expression *elwr = new IntegerExp(e->loc, e->offset / elemsize,     Type::tsize_t);
+                Expression *eupr = new IntegerExp(e->loc, e->offset / elemsize + d, Type::tsize_t);
+
+                // Create a CTFE pointer &val[ofs..ofs+d]
+                result = new SliceExp(e->loc, val, elwr, eupr);
+                result->type = pointee;
+                result = new AddrExp(e->loc, result);
+                result->type = e->type;
+                return;
+            }
+
+            if (!isSafePointerCast(elemtype, pointee))
+            {
+                // It's also OK to cast from &string to string*.
+                if (e->offset == 0 && isSafePointerCast(e->var->type, pointee))
+                {
+                    // Create a CTFE pointer &var
+                    result = new VarExp(e->loc, e->var);
+                    result->type = elemtype;
+                    result = new AddrExp(e->loc, result);
+                    result->type = e->type;
+                    return;
+                }
+                e->error("reinterpreting cast from %s to %s is not supported in CTFE",
+                    val->type->toChars(), e->type->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+
+            dinteger_t sz = pointee->size();
+            dinteger_t indx = e->offset / sz;
+            assert(sz * indx == e->offset);
+            Expression *aggregate = NULL;
+            if (val->op == TOKarrayliteral || val->op == TOKstring)
+            {
+                aggregate = val;
+            }
+            else if (val->op == TOKslice)
+            {
+                aggregate = ((SliceExp *)val)->e1;
+                Expression *lwr = interpret(((SliceExp *)val)->lwr, istate);
+                indx += lwr->toInteger();
+            }
+            if (aggregate)
+            {
+                // Create a CTFE pointer &aggregate[ofs]
+                IntegerExp *ofs = new IntegerExp(e->loc, indx, Type::tsize_t);
+                result = new IndexExp(e->loc, aggregate, ofs);
+                result->type = elemtype;
+                result = new AddrExp(e->loc, result);
+                result->type = e->type;
+                return;
+            }
+        }
+        else if (e->offset == 0 && isSafePointerCast(e->var->type, pointee))
+        {
+            // Create a CTFE pointer &var
+            VarExp *ve = new VarExp(e->loc, e->var);
+            ve->type = e->var->type;
+            result = new AddrExp(e->loc, ve);
+            result->type = e->type;
+            return;
+        }
+
+        e->error("cannot convert &%s to %s at compile time", e->var->type->toChars(), e->type->toChars());
+        result = CTFEExp::cantexp;
+    }
+
+    void visit(AddrExp *e)
+    {
+    #if LOG
+        printf("%s AddrExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        if (e->e1->op == TOKvar && ((VarExp *)e->e1)->var->isDataseg())
+        {
+            // Normally this is already done by optimize()
+            // Do it here in case optimize(WANTvalue) wasn't run before CTFE
+            result = new SymOffExp(e->loc, ((VarExp *)e->e1)->var, 0);
+            result->type = e->type;
+            return;
+        }
+        result = interpret(e->e1, istate, ctfeNeedLvalue);
+        if (result->op == TOKvar && ((VarExp *)result)->var == istate->fd->vthis)
+            result = interpret(result, istate);
+        if (exceptionOrCant(result))
+            return;
+
+        // Return a simplified address expression
+        result = new AddrExp(e->loc, result);
+        result->type = e->type;
+    }
+
+    void visit(DelegateExp *e)
+    {
+    #if LOG
+        printf("%s DelegateExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        // TODO: Really we should create a CTFE-only delegate expression
+        // of a pointer and a funcptr.
+
+        // If it is &nestedfunc, just return it
+        // TODO: We should save the context pointer
+        if (e->e1->op == TOKvar && ((VarExp *)e->e1)->var == e->func)
+        {
+            result = e;
+            return;
+        }
+
+        result = interpret(e->e1, istate);
+        if (exceptionOrCant(result))
+            return;
+        if (result == e->e1)
+        {
+            // If it has already been CTFE'd, just return it
+            result = e;
+        }
+        else
+        {
+            result = new DelegateExp(e->loc, result, e->func, false);
+            result->type = e->type;
+        }
+    }
+
+    static Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal)
+    {
+        Expression *e = CTFEExp::cantexp;
+        if (VarDeclaration *v = d->isVarDeclaration())
+        {
+            /* Magic variable __ctfe always returns true when interpreting
+             */
+            if (v->ident == Id::ctfe)
+                return new IntegerExp(loc, 1, Type::tbool);
+
+            if (!v->originalType && v->_scope)   // semantic() not yet run
+            {
+                v->semantic (v->_scope);
+                if (v->type->ty == Terror)
+                    return CTFEExp::cantexp;
+            }
+
+            if ((v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) &&
+                !hasValue(v) &&
+                v->_init && !v->isCTFE())
+            {
+                if (v->inuse)
+                {
+                    error(loc, "circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+                    return CTFEExp::cantexp;
+                }
+                if (v->_scope)
+                {
+                    v->inuse++;
+                    v->_init = ::semantic(v->_init, v->_scope, v->type, INITinterpret); // might not be run on aggregate members
+                    v->inuse--;
+                }
+                e = initializerToExpression(v->_init, v->type);
+                if (!e)
+                    return CTFEExp::cantexp;
+                assert(e->type);
+
+                if (e->op == TOKconstruct || e->op == TOKblit)
+                {
+                    AssignExp *ae = (AssignExp *)e;
+                    e = ae->e2;
+                }
+
+                if (e->op == TOKerror)
+                {
+                    // FIXME: Ultimately all errors should be detected in prior semantic analysis stage.
+                }
+                else if (v->isDataseg() || (v->storage_class & STCmanifest))
+                {
+                    /* Bugzilla 14304: e is a value that is not yet owned by CTFE.
+                     * Mark as "cached", and use it directly during interpretation.
+                     */
+                    e = scrubCacheValue(v->loc, e);
+                    ctfeStack.saveGlobalConstant(v, e);
+                }
+                else
+                {
+                    v->inuse++;
+                    e = interpret(e, istate);
+                    v->inuse--;
+                    if (CTFEExp::isCantExp(e) && !global.gag && !CtfeStatus::stackTraceCallsToSuppress)
+                        errorSupplemental(loc, "while evaluating %s.init", v->toChars());
+                    if (exceptionOrCantInterpret(e))
+                        return e;
+                }
+            }
+            else if (v->isCTFE() && !hasValue(v))
+            {
+                if (v->_init && v->type->size() != 0)
+                {
+                    if (v->_init->isVoidInitializer())
+                    {
+                        // var should have been initialized when it was created
+                        error(loc, "CTFE internal error: trying to access uninitialized var");
+                        assert(0);
+                        return CTFEExp::cantexp;
+                    }
+                    e = initializerToExpression(v->_init);
+                }
+                else
+                    e = v->type->defaultInitLiteral(e->loc);
+
+                e = interpret(e, istate);
+            }
+            else if (!(v->isDataseg() || v->storage_class & STCmanifest) && !v->isCTFE() && !istate)
+            {
+                error(loc, "variable %s cannot be read at compile time", v->toChars());
+                return CTFEExp::cantexp;
+            }
+            else
+            {
+                e = hasValue(v) ? getValue(v) : NULL;
+                if (!e && !v->isCTFE() && v->isDataseg())
+                {
+                    error(loc, "static variable %s cannot be read at compile time", v->toChars());
+                    return CTFEExp::cantexp;
+                }
+                if (!e)
+                {
+                    assert(!(v->_init && v->_init->isVoidInitializer()));
+                    // CTFE initiated from inside a function
+                    error(loc, "variable %s cannot be read at compile time", v->toChars());
+                    return CTFEExp::cantexp;
+                }
+                if (e->op == TOKvoid)
+                {
+                    VoidInitExp *ve = (VoidInitExp *)e;
+                    error(loc, "cannot read uninitialized variable %s in ctfe", v->toPrettyChars());
+                    errorSupplemental(ve->var->loc, "%s was uninitialized and used before set", ve->var->toChars());
+                    return CTFEExp::cantexp;
+                }
+                if (goal != ctfeNeedLvalue && (v->isRef() || v->isOut()))
+                    e = interpret(e, istate, goal);
+            }
+            if (!e)
+                e = CTFEExp::cantexp;
+        }
+        else if (SymbolDeclaration *s = d->isSymbolDeclaration())
+        {
+            // Struct static initializers, for example
+            e = s->dsym->type->defaultInitLiteral(loc);
+            if (e->op == TOKerror)
+                error(loc, "CTFE failed because of previous errors in %s.init", s->toChars());
+            e = ::semantic(e, NULL);
+            if (e->op == TOKerror)
+                e = CTFEExp::cantexp;
+            else // Convert NULL to CTFEExp
+                e = interpret(e, istate, goal);
+        }
+        else
+            error(loc, "cannot interpret declaration %s at compile time", d->toChars());
+        return e;
+    }
+
+    void visit(VarExp *e)
+    {
+    #if LOG
+        printf("%s VarExp::interpret() %s, goal = %d\n", e->loc.toChars(), e->toChars(), goal);
+    #endif
+        if (e->var->isFuncDeclaration())
+        {
+            result = e;
+            return;
+        }
+
+        if (goal == ctfeNeedLvalue)
+        {
+            VarDeclaration *v = e->var->isVarDeclaration();
+            if (v && !v->isDataseg() && !v->isCTFE() && !istate)
+            {
+                e->error("variable %s cannot be read at compile time", v->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            if (v && !hasValue(v))
+            {
+                if (!v->isCTFE() && v->isDataseg())
+                    e->error("static variable %s cannot be read at compile time", v->toChars());
+                else     // CTFE initiated from inside a function
+                    e->error("variable %s cannot be read at compile time", v->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            if (v && (v->storage_class & (STCout | STCref)) && hasValue(v))
+            {
+                // Strip off the nest of ref variables
+                Expression *ev = getValue(v);
+                if (ev->op == TOKvar ||
+                    ev->op == TOKindex ||
+                    ev->op == TOKdotvar)
+                {
+                    result = interpret(ev, istate, goal);
+                    return;
+                }
+            }
+            result = e;
+            return;
+        }
+        result = getVarExp(e->loc, istate, e->var, goal);
+        if (exceptionOrCant(result))
+            return;
+        if ((e->var->storage_class & (STCref | STCout)) == 0 &&
+            e->type->baseElemOf()->ty != Tstruct)
+        {
+            /* Ultimately, STCref|STCout check should be enough to see the
+             * necessity of type repainting. But currently front-end paints
+             * non-ref struct variables by the const type.
+             *
+             *  auto foo(ref const S cs);
+             *  S s;
+             *  foo(s); // VarExp('s') will have const(S)
+             */
+            // A VarExp may include an implicit cast. It must be done explicitly.
+            result = paintTypeOntoLiteral(e->type, result);
+        }
+    }
+
+    void visit(DeclarationExp *e)
+    {
+    #if LOG
+        printf("%s DeclarationExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        Dsymbol *s = e->declaration;
+        if (VarDeclaration *v = s->isVarDeclaration())
+        {
+            if (TupleDeclaration *td = v->toAlias()->isTupleDeclaration())
+            {
+                result = NULL;
+
+                // Reserve stack space for all tuple members
+                if (!td->objects)
+                    return;
+                for (size_t i = 0; i < td->objects->dim; ++i)
+                {
+                    RootObject * o = (*td->objects)[i];
+                    Expression *ex = isExpression(o);
+                    DsymbolExp *ds = (ex && ex->op == TOKdsymbol) ? (DsymbolExp *)ex : NULL;
+                    VarDeclaration *v2 = ds ? ds->s->isVarDeclaration() : NULL;
+                    assert(v2);
+                    if (v2->isDataseg() && !v2->isCTFE())
+                        continue;
+
+                    ctfeStack.push(v2);
+                    if (v2->_init)
+                    {
+                        Expression *einit;
+                        if (ExpInitializer *ie = v2->_init->isExpInitializer())
+                        {
+                            einit = interpret(ie->exp, istate, goal);
+                            if (exceptionOrCant(einit))
+                                return;
+                        }
+                        else if (v2->_init->isVoidInitializer())
+                        {
+                            einit = voidInitLiteral(v2->type, v2).copy();
+                        }
+                        else
+                        {
+                            e->error("declaration %s is not yet implemented in CTFE", e->toChars());
+                            result = CTFEExp::cantexp;
+                            return;
+                        }
+                        setValue(v2, einit);
+                    }
+                }
+                return;
+            }
+            if (v->isStatic())
+            {
+                // Just ignore static variables which aren't read or written yet
+                result = NULL;
+                return;
+            }
+            if (!(v->isDataseg() || v->storage_class & STCmanifest) || v->isCTFE())
+                ctfeStack.push(v);
+            if (v->_init)
+            {
+                if (ExpInitializer *ie = v->_init->isExpInitializer())
+                {
+                    result = interpret(ie->exp, istate, goal);
+                }
+                else if (v->_init->isVoidInitializer())
+                {
+                    result = voidInitLiteral(v->type, v).copy();
+                    // There is no AssignExp for void initializers,
+                    // so set it here.
+                    setValue(v, result);
+                }
+                else
+                {
+                    e->error("declaration %s is not yet implemented in CTFE", e->toChars());
+                    result = CTFEExp::cantexp;
+                }
+            }
+            else if (v->type->size() == 0)
+            {
+                // Zero-length arrays don't need an initializer
+                result = v->type->defaultInitLiteral(e->loc);
+            }
+            else
+            {
+                e->error("variable %s cannot be modified at compile time", v->toChars());
+                result = CTFEExp::cantexp;
+            }
+            return;
+        }
+        if (s->isAttribDeclaration() ||
+            s->isTemplateMixin() ||
+            s->isTupleDeclaration())
+        {
+            // Check for static struct declarations, which aren't executable
+            AttribDeclaration *ad = e->declaration->isAttribDeclaration();
+            if (ad && ad->decl && ad->decl->dim == 1)
+            {
+                Dsymbol *sparent = (*ad->decl)[0];
+                if (sparent->isAggregateDeclaration() ||
+                    sparent->isTemplateDeclaration() ||
+                    sparent->isAliasDeclaration())
+                {
+                    result = NULL;
+                    return;         // static (template) struct declaration. Nothing to do.
+                }
+            }
+
+            // These can be made to work, too lazy now
+            e->error("declaration %s is not yet implemented in CTFE", e->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        // Others should not contain executable code, so are trivial to evaluate
+        result = NULL;
+    #if LOG
+        printf("-DeclarationExp::interpret(%s): %p\n", e->toChars(), result);
+    #endif
+    }
+
+    void visit(TypeidExp *e)
+    {
+    #if LOG
+        printf("%s TypeidExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        if (Type *t = isType(e->obj))
+        {
+            result = e;
+            return;
+        }
+        if (Expression *ex = isExpression(e->obj))
+        {
+            result = interpret(ex, istate);
+            if (exceptionOrCant(ex))
+                return;
+
+            if (result->op == TOKnull)
+            {
+                e->error("null pointer dereference evaluating typeid. '%s' is null", ex->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            if (result->op != TOKclassreference)
+            {
+                e->error("CTFE internal error: determining classinfo");
+                result = CTFEExp::cantexp;
+                return;
+            }
+
+            ClassDeclaration *cd = ((ClassReferenceExp *)result)->originalClass();
+            assert(cd);
+
+            result = new TypeidExp(e->loc, cd->type);
+            result->type = e->type;
+            return;
+        }
+        visit((Expression *)e);
+    }
+
+    void visit(TupleExp *e)
+    {
+    #if LOG
+        printf("%s TupleExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+
+        if (exceptionOrCant(interpret(e->e0, istate, ctfeNeedNothing)))
+            return;
+
+        Expressions *expsx = NULL;
+        for (size_t i = 0; i < e->exps->dim; i++)
+        {
+            Expression *exp = (*e->exps)[i];
+            Expression *ex = interpret(exp, istate);
+            if (exceptionOrCant(ex))
+                return;
+
+            // A tuple of assignments can contain void (Bug 5676).
+            if (goal == ctfeNeedNothing)
+                continue;
+            if (ex->op == TOKvoidexp)
+            {
+                e->error("CTFE internal error: void element %s in tuple", exp->toChars());
+                assert(0);
+            }
+
+            /* If any changes, do Copy On Write
+             */
+            if (ex != exp)
+            {
+                if (!expsx)
+                {
+                    expsx = new Expressions();
+                    ++CtfeStatus::numArrayAllocs;
+                    expsx->setDim(e->exps->dim);
+                    for (size_t j = 0; j < i; j++)
+                    {
+                        (*expsx)[j] = (*e->exps)[j];
+                    }
+                }
+                (*expsx)[i] = ex;
+            }
+        }
+        if (expsx)
+        {
+            TupleExp *te = new TupleExp(e->loc, expsx);
+            expandTuples(te->exps);
+            te->type = new TypeTuple(te->exps);
+            result = te;
+            return;
+        }
+        result = e;
+        return;
+    }
+
+    void visit(ArrayLiteralExp *e)
+    {
+    #if LOG
+        printf("%s ArrayLiteralExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        if (e->ownedByCtfe >= OWNEDctfe)    // We've already interpreted all the elements
+        {
+            result = e;
+            return;
+        }
+
+        Type *tn = e->type->toBasetype()->nextOf()->toBasetype();
+        bool wantCopy = (tn->ty == Tsarray || tn->ty == Tstruct);
+
+        Expression *basis = interpret(e->basis, istate);
+        if (exceptionOrCant(basis))
+            return;
+
+        Expressions *expsx = NULL;
+        size_t dim = e->elements ? e->elements->dim : 0;
+        for (size_t i = 0; i < dim; i++)
+        {
+            Expression *exp = (*e->elements)[i];
+            Expression *ex;
+            if (!exp)
+            {
+                ex = copyLiteral(basis).copy();
+                goto Lcow;
+            }
+
+            // segfault bug 6250
+            assert(exp->op != TOKindex || ((IndexExp *)exp)->e1 != e);
+
+            ex = interpret(exp, istate);
+            if (exceptionOrCant(ex))
+                return;
+
+            /* Each elements should have distinct CFE memory.
+             *  int[1] z = 7;
+             *  int[1][] pieces = [z,z];    // here
+             */
+            if (wantCopy || ex == exp && expsx)
+                ex = copyLiteral(ex).copy();
+
+            if (ex == exp && !expsx)
+                continue;
+
+            /* If any changes, do Copy On Write
+             */
+        Lcow:
+            if (!expsx)
+            {
+                expsx = new Expressions();
+                ++CtfeStatus::numArrayAllocs;
+                expsx->setDim(dim);
+                for (size_t j = 0; j < i; j++)
+                {
+                    Expression *el = (*e->elements)[j];
+                    if (!el)
+                        el = e->basis;
+                    (*expsx)[j] = copyLiteral(el).copy();
+                }
+            }
+            (*expsx)[i] = ex;
+        }
+        if (expsx)
+        {
+            // todo: all tuple expansions should go in semantic phase.
+            expandTuples(expsx);
+            if (expsx->dim != dim)
+            {
+                e->error("CTFE internal error: invalid array literal");
+                result = CTFEExp::cantexp;
+                return;
+            }
+            ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, basis, expsx);
+            ae->type = e->type;
+            ae->ownedByCtfe = OWNEDctfe;
+            result = ae;
+            return;
+        }
+        if (((TypeNext *)e->type)->next->mod & (MODconst | MODimmutable))
+        {
+            // If it's immutable, we don't need to dup it
+            result = e;
+            return;
+        }
+        result = copyLiteral(e).copy();
+    }
+
+    void visit(AssocArrayLiteralExp *e)
+    {
+        Expressions *keysx = e->keys;
+        Expressions *valuesx = e->values;
+
+    #if LOG
+        printf("%s AssocArrayLiteralExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        if (e->ownedByCtfe >= OWNEDctfe)    // We've already interpreted all the elements
+        {
+            result = e;
+            return;
+        }
+        for (size_t i = 0; i < e->keys->dim; i++)
+        {
+            Expression *ekey = (*e->keys)[i];
+            Expression *evalue = (*e->values)[i];
+
+            Expression *ex = interpret(ekey, istate);
+            if (exceptionOrCant(ex))
+                return;
+
+            /* If any changes, do Copy On Write
+             */
+            if (ex != ekey)
+            {
+                if (keysx == e->keys)
+                    keysx = (Expressions *)e->keys->copy();
+                (*keysx)[i] = ex;
+            }
+
+            ex = interpret(evalue, istate);
+            if (exceptionOrCant(ex))
+                return;
+
+            /* If any changes, do Copy On Write
+             */
+            if (ex != evalue)
+            {
+                if (valuesx == e->values)
+                    valuesx = (Expressions *)e->values->copy();
+                (*valuesx)[i] = ex;
+            }
+        }
+        if (keysx != e->keys)
+            expandTuples(keysx);
+        if (valuesx != e->values)
+            expandTuples(valuesx);
+        if (keysx->dim != valuesx->dim)
+        {
+            e->error("CTFE internal error: invalid AA");
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        /* Remove duplicate keys
+         */
+        for (size_t i = 1; i < keysx->dim; i++)
+        {
+            Expression *ekey = (*keysx)[i - 1];
+            for (size_t j = i; j < keysx->dim; j++)
+            {
+                Expression *ekey2 = (*keysx)[j];
+                int eq = ctfeEqual(e->loc, TOKequal, ekey, ekey2);
+                if (eq)       // if a match
+                {
+                    // Remove ekey
+                    if (keysx == e->keys)
+                        keysx = (Expressions *)e->keys->copy();
+                    if (valuesx == e->values)
+                        valuesx = (Expressions *)e->values->copy();
+                    keysx->remove(i - 1);
+                    valuesx->remove(i - 1);
+                    i -= 1;         // redo the i'th iteration
+                    break;
+                }
+            }
+        }
+
+        if (keysx != e->keys || valuesx != e->values)
+        {
+            AssocArrayLiteralExp *ae;
+            ae = new AssocArrayLiteralExp(e->loc, keysx, valuesx);
+            ae->type = e->type;
+            ae->ownedByCtfe = OWNEDctfe;
+            result = ae;
+            return;
+        }
+        result = copyLiteral(e).copy();
+    }
+
+    void visit(StructLiteralExp *e)
+    {
+    #if LOG
+        printf("%s StructLiteralExp::interpret() %s ownedByCtfe = %d\n", e->loc.toChars(), e->toChars(), e->ownedByCtfe);
+    #endif
+        if (e->ownedByCtfe >= OWNEDctfe)
+        {
+            result = e;
+            return;
+        }
+
+        size_t elemdim = e->elements ? e->elements->dim : 0;
+        Expressions *expsx = NULL;
+        for (size_t i = 0; i < e->sd->fields.dim; i++)
+        {
+            VarDeclaration *v = e->sd->fields[i];
+            Expression *ex = NULL;
+            Expression *exp = NULL;
+            if (i >= elemdim)
+            {
+                /* If a nested struct has no initialized hidden pointer,
+                 * set it to null to match the runtime behaviour.
+                 */
+                if (i == e->sd->fields.dim - 1 && e->sd->isNested())
+                {
+                    // Context field has not been filled
+                    ex = new NullExp(e->loc);
+                    ex->type = v->type;
+                }
+            }
+            else
+            {
+                exp = (*e->elements)[i];
+                if (!exp)
+                {
+                    ex = voidInitLiteral(v->type, v).copy();
+                }
+                else
+                {
+                    ex = interpret(exp, istate);
+                    if (exceptionOrCant(ex))
+                        return;
+                    if ((v->type->ty != ex->type->ty) && v->type->ty == Tsarray)
+                    {
+                        // Block assignment from inside struct literals
+                        TypeSArray *tsa = (TypeSArray *)v->type;
+                        size_t len = (size_t)tsa->dim->toInteger();
+                        ex = createBlockDuplicatedArrayLiteral(ex->loc, v->type, ex, len);
+                    }
+                }
+            }
+
+            /* If any changes, do Copy On Write
+             */
+            if (ex != exp)
+            {
+                if (!expsx)
+                {
+                    expsx = new Expressions();
+                    ++CtfeStatus::numArrayAllocs;
+                    expsx->setDim(e->sd->fields.dim);
+                    for (size_t j = 0; j < e->elements->dim; j++)
+                    {
+                        (*expsx)[j] = (*e->elements)[j];
+                    }
+                }
+                (*expsx)[i] = ex;
+            }
+        }
+
+        if (e->elements && expsx)
+        {
+            expandTuples(expsx);
+            if (expsx->dim != e->sd->fields.dim)
+            {
+                e->error("CTFE internal error: invalid struct literal");
+                result = CTFEExp::cantexp;
+                return;
+            }
+            StructLiteralExp *se = new StructLiteralExp(e->loc, e->sd, expsx);
+            se->type = e->type;
+            se->ownedByCtfe = OWNEDctfe;
+            result = se;
+            return;
+        }
+        result = copyLiteral(e).copy();
+    }
+
+    // Create an array literal of type 'newtype' with dimensions given by
+    // 'arguments'[argnum..$]
+    static Expression *recursivelyCreateArrayLiteral(Loc loc, Type *newtype, InterState *istate,
+        Expressions *arguments, int argnum)
+    {
+        Expression *lenExpr = interpret((*arguments)[argnum], istate);
+        if (exceptionOrCantInterpret(lenExpr))
+            return lenExpr;
+        size_t len = (size_t)(lenExpr->toInteger());
+        Type *elemType = ((TypeArray *)newtype)->next;
+        if (elemType->ty == Tarray && argnum < arguments->dim - 1)
+        {
+            Expression *elem = recursivelyCreateArrayLiteral(loc, elemType, istate,
+                arguments, argnum + 1);
+            if (exceptionOrCantInterpret(elem))
+                return elem;
+
+            Expressions *elements = new Expressions();
+            elements->setDim(len);
+            for (size_t i = 0; i < len; i++)
+                 (*elements)[i] = copyLiteral(elem).copy();
+            ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements);
+            ae->type = newtype;
+            ae->ownedByCtfe = OWNEDctfe;
+            return ae;
+        }
+        assert(argnum == arguments->dim - 1);
+        if (elemType->ty == Tchar || elemType->ty == Twchar || elemType->ty == Tdchar)
+        {
+            const unsigned ch = (unsigned)elemType->defaultInitLiteral(loc)->toInteger();
+            const unsigned char sz = (unsigned char)elemType->size();
+            return createBlockDuplicatedStringLiteral(loc, newtype, ch, len, sz);
+        }
+        else
+        {
+            Expression *el = interpret(elemType->defaultInitLiteral(loc), istate);
+            return createBlockDuplicatedArrayLiteral(loc, newtype, el, len);
+        }
+    }
+
+    void visit(NewExp *e)
+    {
+    #if LOG
+        printf("%s NewExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+
+        if (e->allocator)
+        {
+            e->error("member allocators not supported by CTFE");
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        result = interpret(e->argprefix, istate, ctfeNeedNothing);
+        if (exceptionOrCant(result))
+            return;
+
+        if (e->newtype->ty == Tarray && e->arguments)
+        {
+            result = recursivelyCreateArrayLiteral(e->loc, e->newtype, istate, e->arguments, 0);
+            return;
+        }
+        if (e->newtype->toBasetype()->ty == Tstruct)
+        {
+            if (e->member)
+            {
+                Expression *se = e->newtype->defaultInitLiteral(e->loc);
+                se = interpret(se, istate);
+                if (exceptionOrCant(se))
+                    return;
+                result = interpret(e->member, istate, e->arguments, se);
+
+                // Repaint as same as CallExp::interpret() does.
+                result->loc = e->loc;
+            }
+            else
+            {
+                StructDeclaration *sd = ((TypeStruct *)e->newtype->toBasetype())->sym;
+                Expressions *exps = new Expressions();
+                exps->reserve(sd->fields.dim);
+                if (e->arguments)
+                {
+                    exps->setDim(e->arguments->dim);
+                    for (size_t i = 0; i < exps->dim; i++)
+                    {
+                        Expression *ex = (*e->arguments)[i];
+                        ex = interpret(ex, istate);
+                        if (exceptionOrCant(ex))
+                            return;
+                        (*exps)[i] = ex;
+                    }
+                }
+                sd->fill(e->loc, exps, false);
+
+                StructLiteralExp *se = new StructLiteralExp(e->loc, sd, exps, e->newtype);
+                se->type = e->newtype;
+                se->ownedByCtfe = OWNEDctfe;
+                result = interpret(se, istate);
+            }
+            if (exceptionOrCant(result))
+                return;
+            result = new AddrExp(e->loc, result);
+            result->type = e->type;
+            return;
+        }
+        if (e->newtype->toBasetype()->ty == Tclass)
+        {
+            ClassDeclaration *cd = ((TypeClass *)e->newtype->toBasetype())->sym;
+            size_t totalFieldCount = 0;
+            for (ClassDeclaration *c = cd; c; c = c->baseClass)
+                totalFieldCount += c->fields.dim;
+            Expressions *elems = new Expressions;
+            elems->setDim(totalFieldCount);
+            size_t fieldsSoFar = totalFieldCount;
+            for (ClassDeclaration *c = cd; c; c = c->baseClass)
+            {
+                fieldsSoFar -= c->fields.dim;
+                for (size_t i = 0; i < c->fields.dim; i++)
+                {
+                    VarDeclaration *v = c->fields[i];
+                    if (v->inuse)
+                    {
+                        e->error("circular reference to '%s'", v->toPrettyChars());
+                        result = CTFEExp::cantexp;
+                        return;
+                    }
+                    Expression *m;
+                    if (v->_init)
+                    {
+                        if (v->_init->isVoidInitializer())
+                            m = voidInitLiteral(v->type, v).copy();
+                        else
+                            m = v->getConstInitializer(true);
+                    }
+                    else
+                        m = v->type->defaultInitLiteral(e->loc);
+                    if (exceptionOrCant(m))
+                        return;
+                    (*elems)[fieldsSoFar+i] = copyLiteral(m).copy();
+                }
+            }
+            // Hack: we store a ClassDeclaration instead of a StructDeclaration.
+            // We probably won't get away with this.
+            StructLiteralExp *se = new StructLiteralExp(e->loc, (StructDeclaration *)cd, elems, e->newtype);
+            se->ownedByCtfe = OWNEDctfe;
+            Expression *eref = new ClassReferenceExp(e->loc, se, e->type);
+            if (e->member)
+            {
+                // Call constructor
+                if (!e->member->fbody)
+                {
+                    Expression *ctorfail = evaluateIfBuiltin(istate, e->loc, e->member, e->arguments, eref);
+                    if (ctorfail)
+                    {
+                        if (exceptionOrCant(ctorfail))
+                            return;
+                        result = eref;
+                        return;
+                    }
+                    e->member->error("%s cannot be constructed at compile time, because the constructor has no available source code", e->newtype->toChars());
+                    result = CTFEExp::cantexp;
+                    return;
+                }
+                Expression *ctorfail = interpret(e->member, istate, e->arguments, eref);
+                if (exceptionOrCant(ctorfail))
+                    return;
+
+                /* Bugzilla 14465: Repaint the loc, because a super() call
+                 * in the constructor modifies the loc of ClassReferenceExp
+                 * in CallExp::interpret().
+                 */
+                eref->loc = e->loc;
+            }
+            result = eref;
+            return;
+        }
+        if (e->newtype->toBasetype()->isscalar())
+        {
+            Expression *newval;
+            if (e->arguments && e->arguments->dim)
+                newval = (*e->arguments)[0];
+            else
+                newval = e->newtype->defaultInitLiteral(e->loc);
+            newval = interpret(newval, istate);
+            if (exceptionOrCant(newval))
+                return;
+
+            // Create a CTFE pointer &[newval][0]
+            Expressions *elements = new Expressions();
+            elements->setDim(1);
+            (*elements)[0] = newval;
+            ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, elements);
+            ae->type = e->newtype->arrayOf();
+            ae->ownedByCtfe = OWNEDctfe;
+
+            result = new IndexExp(e->loc, ae, new IntegerExp(Loc(), 0, Type::tsize_t));
+            result->type = e->newtype;
+            result = new AddrExp(e->loc, result);
+            result->type = e->type;
+            return;
+        }
+        e->error("cannot interpret %s at compile time", e->toChars());
+        result = CTFEExp::cantexp;
+    }
+
+    void visit(UnaExp *e)
+    {
+    #if LOG
+        printf("%s UnaExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        Expression *e1 = interpret(e->e1, istate);
+        if (exceptionOrCant(e1))
+            return;
+        UnionExp ue;
+        switch (e->op)
+        {
+            case TOKneg:    ue = Neg(e->type, e1);  break;
+            case TOKtilde:  ue = Com(e->type, e1);  break;
+            case TOKnot:    ue = Not(e->type, e1);  break;
+            case TOKvector: result = e;             return; // do nothing
+            default:        assert(0);
+        }
+        result = ue.copy();
+    }
+
+    void visit(DotTypeExp *e)
+    {
+    #if LOG
+        printf("%s DotTypeExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        Expression *e1 = interpret(e->e1, istate);
+        if (exceptionOrCant(e1))
+            return;
+
+        if (e1 == e->e1)
+            result = e;  // optimize: reuse this CTFE reference
+        else
+        {
+            result = e->copy();
+            ((DotTypeExp *)result)->e1 = e1;
+        }
+    }
+
+    bool evalOperand(Expression *e, Expression *ex, Expression *&er)
+    {
+        er = interpret(ex, istate);
+        if (exceptionOrCant(er))
+            return false;
+        if (er->isConst() != 1)
+        {
+            if (er->op == TOKarrayliteral)
+                // Until we get it to work, issue a reasonable error message
+                e->error("cannot interpret array literal expression %s at compile time", e->toChars());
+            else
+                e->error("CTFE internal error: non-constant value %s", ex->toChars());
+            result = CTFEExp::cantexp;
+            return false;
+        }
+        return true;
+    }
+
+    void interpretCommon(BinExp *e, fp_t fp)
+    {
+    #if LOG
+        printf("%s BinExp::interpretCommon() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        if (e->e1->type->ty == Tpointer && e->e2->type->ty == Tpointer && e->op == TOKmin)
+        {
+            Expression *e1 = interpret(e->e1, istate);
+            if (exceptionOrCant(e1))
+                return;
+            Expression *e2 = interpret(e->e2, istate);
+            if (exceptionOrCant(e2))
+                return;
+            result = pointerDifference(e->loc, e->type, e1, e2).copy();
+            return;
+        }
+        if (e->e1->type->ty == Tpointer && e->e2->type->isintegral())
+        {
+            Expression *e1 = interpret(e->e1, istate);
+            if (exceptionOrCant(e1))
+                return;
+            Expression *e2 = interpret(e->e2, istate);
+            if (exceptionOrCant(e2))
+                return;
+            result = pointerArithmetic(e->loc, e->op, e->type, e1, e2).copy();
+            return;
+        }
+        if (e->e2->type->ty == Tpointer && e->e1->type->isintegral() && e->op == TOKadd)
+        {
+            Expression *e1 = interpret(e->e1, istate);
+            if (exceptionOrCant(e1))
+                return;
+            Expression *e2 = interpret(e->e2, istate);
+            if (exceptionOrCant(e2))
+                return;
+            result = pointerArithmetic(e->loc, e->op, e->type, e2, e1).copy();
+            return;
+        }
+        if (e->e1->type->ty == Tpointer || e->e2->type->ty == Tpointer)
+        {
+            e->error("pointer expression %s cannot be interpreted at compile time", e->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        Expression *e1;
+        if (!evalOperand(e, e->e1, e1))
+            return;
+        Expression *e2;
+        if (!evalOperand(e, e->e2, e2))
+            return;
+
+        if (e->op == TOKshr || e->op == TOKshl || e->op == TOKushr)
+        {
+            sinteger_t i2 = e2->toInteger();
+            d_uns64 sz = e1->type->size() * 8;
+            if (i2 < 0 || i2 >= sz)
+            {
+                e->error("shift by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1);
+                result = CTFEExp::cantexp;
+                return;
+            }
+        }
+        result = (*fp)(e->type, e1, e2).copy();
+        if (CTFEExp::isCantExp(result))
+            e->error("%s cannot be interpreted at compile time", e->toChars());
+    }
+
+    void interpretCompareCommon(BinExp *e, fp2_t fp)
+    {
+    #if LOG
+        printf("%s BinExp::interpretCompareCommon() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        if (e->e1->type->ty == Tpointer && e->e2->type->ty == Tpointer)
+        {
+            Expression *e1 = interpret(e->e1, istate);
+            if (exceptionOrCant(e1))
+                return;
+            Expression *e2 = interpret(e->e2, istate);
+            if (exceptionOrCant(e2))
+                return;
+            //printf("e1 = %s %s, e2 = %s %s\n", e1->type->toChars(), e1->toChars(), e2->type->toChars(), e2->toChars());
+            dinteger_t ofs1, ofs2;
+            Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
+            Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
+            //printf("agg1 = %p %s, agg2 = %p %s\n", agg1, agg1->toChars(), agg2, agg2->toChars());
+            int cmp = comparePointers(e->loc, e->op, e->type, agg1, ofs1, agg2, ofs2);
+            if (cmp == -1)
+            {
+                char dir = (e->op == TOKgt || e->op == TOKge) ? '<' : '>';
+                e->error("the ordering of pointers to unrelated memory blocks is indeterminate in CTFE."
+                         " To check if they point to the same memory block, use both > and < inside && or ||, "
+                         "eg (%s && %s %c= %s + 1)",
+                    e->toChars(), e->e1->toChars(), dir, e->e2->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            result = new IntegerExp(e->loc, cmp, e->type);
+            return;
+        }
+        Expression *e1 = interpret(e->e1, istate);
+        if (exceptionOrCant(e1))
+            return;
+        if (!isCtfeComparable(e1))
+        {
+            e->error("cannot compare %s at compile time", e1->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        Expression *e2 = interpret(e->e2, istate);
+        if (exceptionOrCant(e2))
+            return;
+        if (!isCtfeComparable(e2))
+        {
+            e->error("cannot compare %s at compile time", e2->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        int cmp = (*fp)(e->loc, e->op, e1, e2);
+        result = new IntegerExp(e->loc, cmp, e->type);
+    }
+
+    void visit(BinExp *e)
+    {
+        switch (e->op)
+        {
+        case TOKadd:  interpretCommon(e, &Add);     return;
+        case TOKmin:  interpretCommon(e, &Min);     return;
+        case TOKmul:  interpretCommon(e, &Mul);     return;
+        case TOKdiv:  interpretCommon(e, &Div);     return;
+        case TOKmod:  interpretCommon(e, &Mod);     return;
+        case TOKshl:  interpretCommon(e, &Shl);     return;
+        case TOKshr:  interpretCommon(e, &Shr);     return;
+        case TOKushr: interpretCommon(e, &Ushr);    return;
+        case TOKand:  interpretCommon(e, &And);     return;
+        case TOKor:   interpretCommon(e, &Or);      return;
+        case TOKxor:  interpretCommon(e, &Xor);     return;
+        case TOKpow:  interpretCommon(e, &Pow);     return;
+        case TOKequal:
+        case TOKnotequal:
+            interpretCompareCommon(e, &ctfeEqual);
+            return;
+        case TOKidentity:
+        case TOKnotidentity:
+            interpretCompareCommon(e, &ctfeIdentity);
+            return;
+        case TOKlt:
+        case TOKle:
+        case TOKgt:
+        case TOKge:
+            interpretCompareCommon(e, &ctfeCmp);
+            return;
+        default:
+            printf("be = '%s' %s at [%s]\n", Token::toChars(e->op), e->toChars(), e->loc.toChars());
+            assert(0);
+            return;
+        }
+    }
+
+    /* Helper functions for BinExp::interpretAssignCommon
+     */
+
+    // Returns the variable which is eventually modified, or NULL if an rvalue.
+    // thisval is the current value of 'this'.
+    static VarDeclaration *findParentVar(Expression *e)
+    {
+        for (;;)
+        {
+            if (e->op == TOKvar)
+                break;
+            if (e->op == TOKindex)
+                e = ((IndexExp *)e)->e1;
+            else if (e->op == TOKdotvar)
+                e = ((DotVarExp *)e)->e1;
+            else if (e->op == TOKdotti)
+                e = ((DotTemplateInstanceExp *)e)->e1;
+            else if (e->op == TOKslice)
+                e = ((SliceExp *)e)->e1;
+            else
+                return NULL;
+        }
+        VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
+        assert(v);
+        return v;
+    }
+
+    void interpretAssignCommon(BinExp *e, fp_t fp, int post = 0)
+    {
+    #if LOG
+        printf("%s BinExp::interpretAssignCommon() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        result = CTFEExp::cantexp;
+        Expression *e1 = e->e1;
+        if (!istate)
+        {
+            e->error("value of %s is not known at compile time", e1->toChars());
+            return;
+        }
+
+        ++CtfeStatus::numAssignments;
+
+        /* Before we begin, we need to know if this is a reference assignment
+         * (dynamic array, AA, or class) or a value assignment.
+         * Determining this for slice assignments are tricky: we need to know
+         * if it is a block assignment (a[] = e) rather than a direct slice
+         * assignment (a[] = b[]). Note that initializers of multi-dimensional
+         * static arrays can have 2D block assignments (eg, int[7][7] x = 6;).
+         * So we need to recurse to determine if it is a block assignment.
+         */
+        bool isBlockAssignment = false;
+        if (e1->op == TOKslice)
+        {
+            // a[] = e can have const e. So we compare the naked types.
+            Type *tdst = e1->type->toBasetype();
+            Type *tsrc = e->e2->type->toBasetype();
+            while (tdst->ty == Tsarray || tdst->ty == Tarray)
+            {
+                tdst = ((TypeArray *)tdst)->next->toBasetype();
+                if (tsrc->equivalent(tdst))
+                {
+                    isBlockAssignment = true;
+                    break;
+                }
+            }
+        }
+
+        // ---------------------------------------
+        //      Deal with reference assignment
+        // ---------------------------------------
+        // If it is a construction of a ref variable, it is a ref assignment
+        if ((e->op == TOKconstruct || e->op == TOKblit) &&
+            (((AssignExp *)e)->memset & referenceInit))
+        {
+            assert(!fp);
+
+            Expression *newval = interpret(e->e2, istate, ctfeNeedLvalue);
+            if (exceptionOrCant(newval))
+                return;
+
+            VarDeclaration *v = ((VarExp *)e1)->var->isVarDeclaration();
+            setValue(v, newval);
+
+            // Get the value to return. Note that 'newval' is an Lvalue,
+            // so if we need an Rvalue, we have to interpret again.
+            if (goal == ctfeNeedRvalue)
+                result = interpret(newval, istate);
+            else
+                result = e1;    // VarExp is a CTFE reference
+            return;
+        }
+
+        if (fp)
+        {
+            while (e1->op == TOKcast)
+            {
+                CastExp *ce = (CastExp *)e1;
+                e1 = ce->e1;
+            }
+        }
+
+        // ---------------------------------------
+        //      Interpret left hand side
+        // ---------------------------------------
+        AssocArrayLiteralExp *existingAA = NULL;
+        Expression *lastIndex = NULL;
+        Expression *oldval = NULL;
+        if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray)
+        {
+            // ---------------------------------------
+            //      Deal with AA index assignment
+            // ---------------------------------------
+            /* This needs special treatment if the AA doesn't exist yet.
+             * There are two special cases:
+             * (1) If the AA is itself an index of another AA, we may need to create
+             *     multiple nested AA literals before we can insert the new value.
+             * (2) If the ultimate AA is null, no insertion happens at all. Instead,
+             *     we create nested AA literals, and change it into a assignment.
+             */
+            IndexExp *ie = (IndexExp *)e1;
+            int depth = 0;   // how many nested AA indices are there?
+            while (ie->e1->op == TOKindex &&
+                   ((IndexExp *)ie->e1)->e1->type->toBasetype()->ty == Taarray)
+            {
+                assert(ie->modifiable);
+                ie = (IndexExp *)ie->e1;
+                ++depth;
+            }
+
+            // Get the AA value to be modified.
+            Expression *aggregate = interpret(ie->e1, istate);
+            if (exceptionOrCant(aggregate))
+                return;
+            if (aggregate->op == TOKassocarrayliteral)
+            {
+                existingAA = (AssocArrayLiteralExp *)aggregate;
+
+                // Normal case, ultimate parent AA already exists
+                // We need to walk from the deepest index up, checking that an AA literal
+                // already exists on each level.
+                lastIndex = interpret(((IndexExp *)e1)->e2, istate);
+                lastIndex = resolveSlice(lastIndex);    // only happens with AA assignment
+                if (exceptionOrCant(lastIndex))
+                    return;
+
+                while (depth > 0)
+                {
+                    // Walk the syntax tree to find the indexExp at this depth
+                    IndexExp *xe = (IndexExp *)e1;
+                    for (int d= 0; d < depth; ++d)
+                        xe = (IndexExp *)xe->e1;
+
+                    Expression *ekey = interpret(xe->e2, istate);
+                    if (exceptionOrCant(ekey))
+                        return;
+                    ekey = resolveSlice(ekey);  // only happens with AA assignment
+
+                    // Look up this index in it up in the existing AA, to get the next level of AA.
+                    AssocArrayLiteralExp *newAA = (AssocArrayLiteralExp *)findKeyInAA(e->loc, existingAA, ekey);
+                    if (exceptionOrCant(newAA))
+                        return;
+                    if (!newAA)
+                    {
+                        // Doesn't exist yet, create an empty AA...
+                        Expressions *keysx = new Expressions();
+                        Expressions *valuesx = new Expressions();
+                        newAA = new AssocArrayLiteralExp(e->loc, keysx, valuesx);
+                        newAA->type = xe->type;
+                        newAA->ownedByCtfe = OWNEDctfe;
+                        //... and insert it into the existing AA.
+                        existingAA->keys->push(ekey);
+                        existingAA->values->push(newAA);
+                    }
+                    existingAA = newAA;
+                    --depth;
+                }
+
+                if (fp)
+                {
+                    oldval = findKeyInAA(e->loc, existingAA, lastIndex);
+                    if (!oldval)
+                        oldval = copyLiteral(e->e1->type->defaultInitLiteral(e->loc)).copy();
+                }
+            }
+            else
+            {
+                /* The AA is currently null. 'aggregate' is actually a reference to
+                 * whatever contains it. It could be anything: var, dotvarexp, ...
+                 * We rewrite the assignment from:
+                 *     aa[i][j] op= newval;
+                 * into:
+                 *     aa = [i:[j:T.init]];
+                 *     aa[j] op= newval;
+                 */
+                oldval = copyLiteral(e->e1->type->defaultInitLiteral(e->loc)).copy();
+
+                Expression *newaae = oldval;
+                while (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray)
+                {
+                    Expression *ekey = interpret(((IndexExp *)e1)->e2, istate);
+                    if (exceptionOrCant(ekey))
+                        return;
+                    ekey = resolveSlice(ekey);  // only happens with AA assignment
+                    Expressions *keysx = new Expressions();
+                    Expressions *valuesx = new Expressions();
+                    keysx->push(ekey);
+                    valuesx->push(newaae);
+                    AssocArrayLiteralExp *aae = new AssocArrayLiteralExp(e->loc, keysx, valuesx);
+                    aae->type = ((IndexExp *)e1)->e1->type;
+                    aae->ownedByCtfe = OWNEDctfe;
+                    if (!existingAA)
+                    {
+                        existingAA = aae;
+                        lastIndex = ekey;
+                    }
+                    newaae = aae;
+                    e1 = ((IndexExp *)e1)->e1;
+                }
+
+                // We must set to aggregate with newaae
+                e1 = interpret(e1, istate, ctfeNeedLvalue);
+                if (exceptionOrCant(e1))
+                    return;
+                e1 = assignToLvalue(e, e1, newaae);
+                if (exceptionOrCant(e1))
+                    return;
+            }
+            assert(existingAA && lastIndex);
+            e1 = NULL;  // stomp
+        }
+        else if (e1->op == TOKarraylength)
+        {
+            oldval = interpret(e1, istate);
+            if (exceptionOrCant(oldval))
+                return;
+        }
+        else if (e->op == TOKconstruct || e->op == TOKblit)
+        {
+            // Unless we have a simple var assignment, we're
+            // only modifying part of the variable. So we need to make sure
+            // that the parent variable exists.
+            VarDeclaration *ultimateVar = findParentVar(e1);
+            if (e1->op == TOKvar)
+            {
+                VarDeclaration *v = ((VarExp *)e1)->var->isVarDeclaration();
+                assert(v);
+                if (v->storage_class & STCout)
+                    goto L1;
+            }
+            else if (ultimateVar && !getValue(ultimateVar))
+            {
+                Expression *ex = interpret(ultimateVar->type->defaultInitLiteral(e->loc), istate);
+                if (exceptionOrCant(ex))
+                    return;
+                setValue(ultimateVar, ex);
+            }
+            else
+                goto L1;
+        }
+        else
+        {
+        L1:
+            e1 = interpret(e1, istate, ctfeNeedLvalue);
+            if (exceptionOrCant(e1))
+                return;
+
+            if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray)
+            {
+                IndexExp *ie = (IndexExp *)e1;
+                assert(ie->e1->op == TOKassocarrayliteral);
+                existingAA = (AssocArrayLiteralExp *)ie->e1;
+                lastIndex = ie->e2;
+            }
+        }
+
+        // If it isn't a simple assignment, we need the existing value
+        if (fp && !oldval)
+        {
+            oldval = interpret(e1, istate);
+            if (exceptionOrCant(oldval))
+                return;
+        }
+
+        // ---------------------------------------
+        //      Interpret right hand side
+        // ---------------------------------------
+        Expression *newval = interpret(e->e2, istate);
+        if (exceptionOrCant(newval))
+            return;
+        if (e->op == TOKblit && newval->op == TOKint64)
+        {
+            Type *tbn = e->type->baseElemOf();
+            if (tbn->ty == Tstruct)
+            {
+                /* Look for special case of struct being initialized with 0.
+                 */
+                newval = e->type->defaultInitLiteral(e->loc);
+                if (newval->op == TOKerror)
+                {
+                    result = CTFEExp::cantexp;
+                    return;
+                }
+                newval = interpret(newval, istate); // copy and set ownedByCtfe flag
+                if (exceptionOrCant(newval))
+                    return;
+            }
+        }
+
+        // ----------------------------------------------------
+        //  Deal with read-modify-write assignments.
+        //  Set 'newval' to the final assignment value
+        //  Also determine the return value (except for slice
+        //  assignments, which are more complicated)
+        // ----------------------------------------------------
+        if (fp)
+        {
+            assert(oldval);
+            if (e->e1->type->ty != Tpointer)
+            {
+                // ~= can create new values (see bug 6052)
+                if (e->op == TOKcatass)
+                {
+                    // We need to dup it and repaint the type. For a dynamic array
+                    // we can skip duplication, because it gets copied later anyway.
+                    if (newval->type->ty != Tarray)
+                    {
+                        newval = copyLiteral(newval).copy();
+                        newval->type = e->e2->type; // repaint type
+                    }
+                    else
+                    {
+                        newval = paintTypeOntoLiteral(e->e2->type, newval);
+                        newval = resolveSlice(newval);
+                    }
+                }
+                oldval = resolveSlice(oldval);
+
+                newval = (*fp)(e->type, oldval, newval).copy();
+            }
+            else if (e->e2->type->isintegral() &&
+                (e->op == TOKaddass ||
+                 e->op == TOKminass ||
+                 e->op == TOKplusplus ||
+                 e->op == TOKminusminus))
+            {
+                newval = pointerArithmetic(e->loc, e->op, e->type, oldval, newval).copy();
+            }
+            else
+            {
+                e->error("pointer expression %s cannot be interpreted at compile time", e->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            if (exceptionOrCant(newval))
+            {
+                if (CTFEExp::isCantExp(newval))
+                    e->error("cannot interpret %s at compile time", e->toChars());
+                return;
+            }
+        }
+
+        if (existingAA)
+        {
+            if (existingAA->ownedByCtfe != OWNEDctfe)
+            {
+                e->error("cannot modify read-only constant %s", existingAA->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+
+            //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n",
+            //    __LINE__, existingAA->toChars(), lastIndex->toChars(), oldval ? oldval->toChars() : NULL, newval->toChars());
+            assignAssocArrayElement(e->loc, existingAA, lastIndex, newval);
+
+            // Determine the return value
+            result = ctfeCast(e->loc, e->type, e->type, fp && post ? oldval : newval);
+            return;
+        }
+        if (e1->op == TOKarraylength)
+        {
+            /* Change the assignment from:
+             *  arr.length = n;
+             * into:
+             *  arr = new_length_array; (result is n)
+             */
+
+            // Determine the return value
+            result = ctfeCast(e->loc, e->type, e->type, fp && post ? oldval : newval);
+            if (exceptionOrCant(result))
+                return;
+
+            size_t oldlen = (size_t)oldval->toInteger();
+            size_t newlen = (size_t)newval->toInteger();
+            if (oldlen == newlen) // no change required -- we're done!
+                return;
+
+            // We have changed it into a reference assignment
+            // Note that returnValue is still the new length.
+            e1 = ((ArrayLengthExp *)e1)->e1;
+            Type *t = e1->type->toBasetype();
+            if (t->ty != Tarray)
+            {
+                e->error("%s is not yet supported at compile time", e->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            e1 = interpret(e1, istate, ctfeNeedLvalue);
+            if (exceptionOrCant(e1))
+                return;
+
+            if (oldlen != 0)    // Get the old array literal.
+                oldval = interpret(e1, istate);
+            newval = changeArrayLiteralLength(e->loc, (TypeArray *)t, oldval,
+                oldlen,  newlen).copy();
+
+            e1 = assignToLvalue(e, e1, newval);
+            if (exceptionOrCant(e1))
+                return;
+
+            return;
+        }
+
+        if (!isBlockAssignment)
+        {
+            newval = ctfeCast(e->loc, e->type, e->type, newval);
+            if (exceptionOrCant(newval))
+                return;
+
+            // Determine the return value
+            if (goal == ctfeNeedLvalue)     // Bugzilla 14371
+                result = e1;
+            else
+                result = ctfeCast(e->loc, e->type, e->type, fp && post ? oldval : newval);
+            if (exceptionOrCant(result))
+                return;
+        }
+        if (exceptionOrCant(newval))
+            return;
+
+    #if LOGASSIGN
+        printf("ASSIGN: %s=%s\n", e1->toChars(), newval->toChars());
+        showCtfeExpr(newval);
+    #endif
+
+        /* Block assignment or element-wise assignment.
+         */
+        if (e1->op == TOKslice ||
+            e1->op == TOKvector ||
+            e1->op == TOKarrayliteral ||
+            e1->op == TOKstring ||
+            e1->op == TOKnull && e1->type->toBasetype()->ty == Tarray)
+        {
+            // Note that slice assignments don't support things like ++, so
+            // we don't need to remember 'returnValue'.
+            result = interpretAssignToSlice(e, e1, newval, isBlockAssignment);
+            if (exceptionOrCant(result))
+                return;
+            if (e->e1->op == TOKslice)
+            {
+                Expression *e1x = interpret(((SliceExp*)e->e1)->e1, istate, ctfeNeedLvalue);
+                if (e1x->op == TOKdotvar)
+                {
+                    DotVarExp *dve = (DotVarExp*)e1x;
+                    Expression *ex = dve->e1;
+                    StructLiteralExp *sle = ex->op == TOKstructliteral  ? ((StructLiteralExp  *)ex)
+                                          : ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value
+                                          : NULL;
+                    VarDeclaration *v = dve->var->isVarDeclaration();
+                    if (!sle || !v)
+                    {
+                        e->error("CTFE internal error: dotvar slice assignment");
+                        result = CTFEExp::cantexp;
+                        return;
+                    }
+                    stompOverlappedFields(sle, v);
+                }
+            }
+            return;
+        }
+
+        assert(result);
+
+        /* Assignment to a CTFE reference.
+         */
+        if (Expression *ex = assignToLvalue(e, e1, newval))
+            result = ex;
+
+        return;
+    }
+
+    /* Set all sibling fields which overlap with v to VoidExp.
+     */
+    void stompOverlappedFields(StructLiteralExp *sle, VarDeclaration *v)
+    {
+        if (!v->overlapped)
+            return;
+
+        for (size_t i = 0; i < sle->sd->fields.dim; i++)
+        {
+            VarDeclaration *v2 = sle->sd->fields[i];
+            if (v == v2 || !v->isOverlappedWith(v2))
+                continue;
+            Expression *e = (*sle->elements)[i];
+            if (e->op != TOKvoid)
+                (*sle->elements)[i] = voidInitLiteral(e->type, v).copy();
+        }
+    }
+
+    Expression *assignToLvalue(BinExp *e, Expression *e1, Expression *newval)
+    {
+        VarDeclaration *vd = NULL;
+        Expression **payload = NULL;    // dead-store to prevent spurious warning
+        Expression *oldval;
+
+        if (e1->op == TOKvar)
+        {
+            vd = ((VarExp *)e1)->var->isVarDeclaration();
+            oldval = getValue(vd);
+        }
+        else if (e1->op == TOKdotvar)
+        {
+            /* Assignment to member variable of the form:
+             *  e.v = newval
+             */
+            Expression *ex = ((DotVarExp *)e1)->e1;
+            StructLiteralExp *sle =
+                ex->op == TOKstructliteral  ? ((StructLiteralExp  *)ex):
+                ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value
+                : NULL;
+            VarDeclaration *v = ((DotVarExp *)e1)->var->isVarDeclaration();
+            if (!sle || !v)
+            {
+                e->error("CTFE internal error: dotvar assignment");
+                return CTFEExp::cantexp;
+            }
+            if (sle->ownedByCtfe != OWNEDctfe)
+            {
+                e->error("cannot modify read-only constant %s", sle->toChars());
+                return CTFEExp::cantexp;
+            }
+
+            int fieldi = ex->op == TOKstructliteral
+                ? findFieldIndexByName(sle->sd, v)
+                : ((ClassReferenceExp *)ex)->findFieldIndexByName(v);
+            if (fieldi == -1)
+            {
+                e->error("CTFE internal error: cannot find field %s in %s", v->toChars(), ex->toChars());
+                return CTFEExp::cantexp;
+            }
+            assert(0 <= fieldi && fieldi < sle->elements->dim);
+
+            // If it's a union, set all other members of this union to void
+            stompOverlappedFields(sle, v);
+
+            payload = &(*sle->elements)[fieldi];
+            oldval = *payload;
+        }
+        else if (e1->op == TOKindex)
+        {
+            IndexExp *ie = (IndexExp *)e1;
+            assert(ie->e1->type->toBasetype()->ty != Taarray);
+
+            Expression *aggregate;
+            uinteger_t indexToModify;
+            if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true))
+            {
+                return CTFEExp::cantexp;
+            }
+            size_t index = (size_t)indexToModify;
+
+            if (aggregate->op == TOKstring)
+            {
+                StringExp *existingSE = (StringExp *)aggregate;
+                if (existingSE->ownedByCtfe != OWNEDctfe)
+                {
+                    e->error("cannot modify read-only string literal %s", ie->e1->toChars());
+                    return CTFEExp::cantexp;
+                }
+                void *s = existingSE->string;
+                dinteger_t value = newval->toInteger();
+                switch (existingSE->sz)
+                {
+                    case 1:     (( utf8_t *)s)[index] = ( utf8_t)value; break;
+                    case 2:     ((utf16_t *)s)[index] = (utf16_t)value; break;
+                    case 4:     ((utf32_t *)s)[index] = (utf32_t)value; break;
+                    default:    assert(0);                              break;
+                }
+                return NULL;
+            }
+            if (aggregate->op != TOKarrayliteral)
+            {
+                e->error("index assignment %s is not yet supported in CTFE ", e->toChars());
+                return CTFEExp::cantexp;
+            }
+
+            ArrayLiteralExp *existingAE = (ArrayLiteralExp *)aggregate;
+            if (existingAE->ownedByCtfe != OWNEDctfe)
+            {
+                e->error("cannot modify read-only constant %s", existingAE->toChars());
+                return CTFEExp::cantexp;
+            }
+
+            payload = &(*existingAE->elements)[index];
+            oldval = *payload;
+        }
+        else
+        {
+            e->error("%s cannot be evaluated at compile time", e->toChars());
+            return CTFEExp::cantexp;
+        }
+
+        Type *t1b = e1->type->toBasetype();
+        bool wantCopy = t1b->baseElemOf()->ty == Tstruct;
+
+        if (newval->op == TOKstructliteral && oldval)
+        {
+            newval = copyLiteral(newval).copy();
+            assignInPlace(oldval, newval);
+        }
+        else if (wantCopy && e->op == TOKassign)
+        {
+            // Currently postblit/destructor calls on static array are done
+            // in the druntime internal functions so they don't appear in AST.
+            // Therefore interpreter should handle them specially.
+
+            assert(oldval);
+        #if 1   // todo: instead we can directly access to each elements of the slice
+            newval = resolveSlice(newval);
+            if (CTFEExp::isCantExp(newval))
+            {
+                e->error("CTFE internal error: assignment %s", e->toChars());
+                return CTFEExp::cantexp;
+            }
+        #endif
+            assert(oldval->op == TOKarrayliteral);
+            assert(newval->op == TOKarrayliteral);
+
+            Expressions *oldelems = ((ArrayLiteralExp *)oldval)->elements;
+            Expressions *newelems = ((ArrayLiteralExp *)newval)->elements;
+            assert(oldelems->dim == newelems->dim);
+
+            Type *elemtype = oldval->type->nextOf();
+            for (size_t i = 0; i < newelems->dim; i++)
+            {
+                Expression *oldelem = (*oldelems)[i];
+                Expression *newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]);
+                // Bugzilla 9245
+                if (e->e2->isLvalue())
+                {
+                    if (Expression *ex = evaluatePostblit(istate, newelem))
+                        return ex;
+                }
+                // Bugzilla 13661
+                if (Expression *ex = evaluateDtor(istate, oldelem))
+                    return ex;
+                (*oldelems)[i] = newelem;
+            }
+        }
+        else
+        {
+            // e1 has its own payload, so we have to create a new literal.
+            if (wantCopy)
+                newval = copyLiteral(newval).copy();
+
+            if (t1b->ty == Tsarray && e->op == TOKconstruct && e->e2->isLvalue())
+            {
+                // Bugzilla 9245
+                if (Expression *ex = evaluatePostblit(istate, newval))
+                    return ex;
+            }
+
+            oldval = newval;
+        }
+
+        if (vd)
+            setValue(vd, oldval);
+        else
+            *payload = oldval;
+
+        // Blit assignment should return the newly created value.
+        if (e->op == TOKblit)
+            return oldval;
+
+        return NULL;
+    }
+
+    /*************
+     * Deal with assignments of the form:
+     *  dest[] = newval
+     *  dest[low..upp] = newval
+     * where newval has already been interpreted
+     *
+     * This could be a slice assignment or a block assignment, and
+     * dest could be either an array literal, or a string.
+     *
+     * Returns TOKcantexp on failure. If there are no errors,
+     * it returns aggregate[low..upp], except that as an optimisation,
+     * if goal == ctfeNeedNothing, it will return NULL
+     */
+    Expression *interpretAssignToSlice(BinExp *e,
+        Expression *e1, Expression *newval, bool isBlockAssignment)
+    {
+        int lowerbound;
+        size_t upperbound;
+
+        Expression *aggregate;
+        sinteger_t firstIndex;
+
+        if (e1->op == TOKvector)
+            e1 = ((VectorExp *)e1)->e1;
+        if (e1->op == TOKslice)
+        {
+            // ------------------------------
+            //   aggregate[] = newval
+            //   aggregate[low..upp] = newval
+            // ------------------------------
+
+            SliceExp *se = (SliceExp *)e1;
+        #if 1   // should be move in interpretAssignCommon as the evaluation of e1
+            Expression *oldval = interpret(se->e1, istate);
+
+            // Set the $ variable
+            uinteger_t dollar = resolveArrayLength(oldval);
+            if (se->lengthVar)
+            {
+                Expression *dollarExp = new IntegerExp(e1->loc, dollar, Type::tsize_t);
+                ctfeStack.push(se->lengthVar);
+                setValue(se->lengthVar, dollarExp);
+            }
+            Expression *lwr = interpret(se->lwr, istate);
+            if (exceptionOrCantInterpret(lwr))
+            {
+                if (se->lengthVar)
+                    ctfeStack.pop(se->lengthVar);
+                return lwr;
+            }
+            Expression *upr = interpret(se->upr, istate);
+            if (exceptionOrCantInterpret(upr))
+            {
+                if (se->lengthVar)
+                    ctfeStack.pop(se->lengthVar);
+                return upr;
+            }
+            if (se->lengthVar)
+                ctfeStack.pop(se->lengthVar); // $ is defined only in [L..U]
+
+            unsigned dim = (unsigned)dollar;
+            lowerbound = (int)(lwr ? lwr->toInteger() : 0);
+            upperbound = (size_t)(upr ? upr->toInteger() : dim);
+
+            if ((int)lowerbound < 0 || dim < upperbound)
+            {
+                e->error("array bounds [0..%d] exceeded in slice [%d..%d]",
+                    dim, lowerbound, upperbound);
+                return CTFEExp::cantexp;
+            }
+        #endif
+            aggregate = oldval;
+            firstIndex = lowerbound;
+
+            if (aggregate->op == TOKslice)
+            {
+                // Slice of a slice --> change the bounds
+                SliceExp *oldse = (SliceExp *)aggregate;
+                if (oldse->upr->toInteger() < upperbound + oldse->lwr->toInteger())
+                {
+                    e->error("slice [%d..%d] exceeds array bounds [0..%lld]",
+                        lowerbound, upperbound,
+                        oldse->upr->toInteger() - oldse->lwr->toInteger());
+                    return CTFEExp::cantexp;
+                }
+                aggregate = oldse->e1;
+                firstIndex = lowerbound + oldse->lwr->toInteger();
+            }
+        }
+        else
+        {
+            if (e1->op == TOKarrayliteral)
+            {
+                lowerbound = 0;
+                upperbound = ((ArrayLiteralExp *)e1)->elements->dim;
+            }
+            else if (e1->op == TOKstring)
+            {
+                lowerbound = 0;
+                upperbound = ((StringExp *)e1)->len;
+            }
+            else if (e1->op == TOKnull)
+            {
+                lowerbound = 0;
+                upperbound = 0;
+            }
+            else
+                assert(0);
+
+            aggregate = e1;
+            firstIndex = lowerbound;
+        }
+        if (upperbound == lowerbound)
+            return newval;
+
+        // For slice assignment, we check that the lengths match.
+        if (!isBlockAssignment)
+        {
+            size_t srclen = (size_t)resolveArrayLength(newval);
+            if (srclen != (upperbound - lowerbound))
+            {
+                e->error("array length mismatch assigning [0..%d] to [%d..%d]",
+                    srclen, lowerbound, upperbound);
+                return CTFEExp::cantexp;
+            }
+        }
+
+        if (aggregate->op == TOKstring)
+        {
+            StringExp *existingSE = (StringExp *)aggregate;
+            if (existingSE->ownedByCtfe != OWNEDctfe)
+            {
+                e->error("cannot modify read-only string literal %s", existingSE->toChars());
+                return CTFEExp::cantexp;
+            }
+
+            if (newval->op == TOKslice)
+            {
+                SliceExp *se = (SliceExp *)newval;
+                Expression *aggr2 = se->e1;
+                const dinteger_t srclower = se->lwr->toInteger();
+                const dinteger_t srcupper = se->upr->toInteger();
+
+                if (aggregate == aggr2 &&
+                    lowerbound < srcupper && srclower < upperbound)
+                {
+                    e->error("overlapping slice assignment [%d..%d] = [%llu..%llu]",
+                        lowerbound, upperbound, srclower, srcupper);
+                    return CTFEExp::cantexp;
+                }
+            #if 1   // todo: instead we can directly access to each elements of the slice
+                Expression *orignewval = newval;
+                newval = resolveSlice(newval);
+                if (CTFEExp::isCantExp(newval))
+                {
+                    e->error("CTFE internal error: slice %s", orignewval->toChars());
+                    return CTFEExp::cantexp;
+                }
+            #endif
+                assert(newval->op != TOKslice);
+            }
+            if (newval->op == TOKstring)
+            {
+                sliceAssignStringFromString((StringExp *)existingSE, (StringExp *)newval, (size_t)firstIndex);
+                return newval;
+            }
+            if (newval->op == TOKarrayliteral)
+            {
+                /* Mixed slice: it was initialized as a string literal.
+                 * Now a slice of it is being set with an array literal.
+                 */
+                sliceAssignStringFromArrayLiteral(existingSE, (ArrayLiteralExp *)newval, (size_t)firstIndex);
+                return newval;
+            }
+
+            // String literal block slice assign
+            dinteger_t value = newval->toInteger();
+            void *s = existingSE->string;
+            for (size_t i = 0; i < upperbound - lowerbound; i++)
+            {
+                switch (existingSE->sz)
+                {
+                    case 1:     (( utf8_t *)s)[(size_t)(i + firstIndex)] = ( utf8_t)value;  break;
+                    case 2:     ((utf16_t *)s)[(size_t)(i + firstIndex)] = (utf16_t)value;  break;
+                    case 4:     ((utf32_t *)s)[(size_t)(i + firstIndex)] = (utf32_t)value;  break;
+                    default:    assert(0);                                                  break;
+                }
+            }
+            if (goal == ctfeNeedNothing)
+                return NULL; // avoid creating an unused literal
+            SliceExp *retslice = new SliceExp(e->loc, existingSE,
+                new IntegerExp(e->loc, firstIndex, Type::tsize_t),
+                new IntegerExp(e->loc, firstIndex + upperbound - lowerbound, Type::tsize_t));
+            retslice->type = e->type;
+            return interpret(retslice, istate);
+        }
+        if (aggregate->op == TOKarrayliteral)
+        {
+            ArrayLiteralExp *existingAE = (ArrayLiteralExp *)aggregate;
+            if (existingAE->ownedByCtfe != OWNEDctfe)
+            {
+                e->error("cannot modify read-only constant %s", existingAE->toChars());
+                return CTFEExp::cantexp;
+            }
+
+            if (newval->op == TOKslice && !isBlockAssignment)
+            {
+                SliceExp *se = (SliceExp *)newval;
+                Expression *aggr2 = se->e1;
+                const dinteger_t srclower = se->lwr->toInteger();
+                const dinteger_t srcupper = se->upr->toInteger();
+                const bool wantCopy = (newval->type->toBasetype()->nextOf()->baseElemOf()->ty == Tstruct);
+
+                //printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n",
+                //    aggregate, aggregate->toChars(), lowerbound, upperbound,
+                //    aggr2, aggr2->toChars(), srclower, srcupper, wantCopy);
+                if (wantCopy)
+                {
+                    // Currently overlapping for struct array is allowed.
+                    // The order of elements processing depends on the overlapping.
+                    // See bugzilla 14024.
+                    assert(aggr2->op == TOKarrayliteral);
+                    Expressions *oldelems = existingAE->elements;
+                    Expressions *newelems = ((ArrayLiteralExp *)aggr2)->elements;
+
+                    Type *elemtype = aggregate->type->nextOf();
+                    bool needsPostblit = e->e2->isLvalue();
+
+                    if (aggregate == aggr2 &&
+                        srclower < lowerbound && lowerbound < srcupper)
+                    {
+                        // reverse order
+                        for (size_t i = upperbound - lowerbound; 0 < i--; )
+                        {
+                            Expression *oldelem = (*oldelems)[(size_t)(i + firstIndex)];
+                            Expression *newelem = (*newelems)[(size_t)(i + srclower)];
+                            newelem = copyLiteral(newelem).copy();
+                            newelem->type = elemtype;
+                            if (needsPostblit)
+                            {
+                                if (Expression *x = evaluatePostblit(istate, newelem))
+                                    return x;
+                            }
+                            if (Expression *x = evaluateDtor(istate, oldelem))
+                                return x;
+                            (*oldelems)[lowerbound + i] = newelem;
+                        }
+                    }
+                    else
+                    {
+                        // normal order
+                        for (size_t i = 0; i < upperbound - lowerbound; i++)
+                        {
+                            Expression *oldelem = (*oldelems)[(size_t)(i + firstIndex)];
+                            Expression *newelem = (*newelems)[(size_t)(i + srclower)];
+                            newelem = copyLiteral(newelem).copy();
+                            newelem->type = elemtype;
+                            if (needsPostblit)
+                            {
+                                if (Expression *x = evaluatePostblit(istate, newelem))
+                                    return x;
+                            }
+                            if (Expression *x = evaluateDtor(istate, oldelem))
+                                return x;
+                            (*oldelems)[lowerbound + i] = newelem;
+                        }
+                    }
+
+                    //assert(0);
+                    return newval;  // oldval?
+                }
+                if (aggregate == aggr2 &&
+                    lowerbound < srcupper && srclower < upperbound)
+                {
+                    e->error("overlapping slice assignment [%d..%d] = [%llu..%llu]",
+                        lowerbound, upperbound, srclower, srcupper);
+                    return CTFEExp::cantexp;
+                }
+            #if 1   // todo: instead we can directly access to each elements of the slice
+                Expression *orignewval = newval;
+                newval = resolveSlice(newval);
+                if (CTFEExp::isCantExp(newval))
+                {
+                    e->error("CTFE internal error: slice %s", orignewval->toChars());
+                    return CTFEExp::cantexp;
+                }
+            #endif
+                // no overlapping
+                //length?
+                assert(newval->op != TOKslice);
+            }
+            if (newval->op == TOKstring && !isBlockAssignment)
+            {
+                /* Mixed slice: it was initialized as an array literal of chars/integers.
+                 * Now a slice of it is being set with a string.
+                 */
+                sliceAssignArrayLiteralFromString(existingAE, (StringExp *)newval, (size_t)firstIndex);
+                return newval;
+            }
+            if (newval->op == TOKarrayliteral && !isBlockAssignment)
+            {
+                Expressions *oldelems = existingAE->elements;
+                Expressions *newelems = ((ArrayLiteralExp *)newval)->elements;
+                Type *elemtype = existingAE->type->nextOf();
+                bool needsPostblit = e->op != TOKblit && e->e2->isLvalue();
+                for (size_t j = 0; j < newelems->dim; j++)
+                {
+                    Expression *newelem = (*newelems)[j];
+                    newelem = paintTypeOntoLiteral(elemtype, newelem);
+                    if (needsPostblit)
+                    {
+                        Expression *x = evaluatePostblit(istate, newelem);
+                        if (exceptionOrCantInterpret(x))
+                            return x;
+                    }
+                    (*oldelems)[(size_t)(j + firstIndex)] = newelem;
+                }
+                return newval;
+            }
+
+            /* Block assignment, initialization of static arrays
+             *   x[] = newval
+             *  x may be a multidimensional static array. (Note that this
+             *  only happens with array literals, never with strings).
+             */
+            struct RecursiveBlock
+            {
+                InterState *istate;
+                Expression *newval;
+                bool refCopy;
+                bool needsPostblit;
+                bool needsDtor;
+
+                Expression *assignTo(ArrayLiteralExp *ae)
+                {
+                    return assignTo(ae, 0, ae->elements->dim);
+                }
+
+                Expression *assignTo(ArrayLiteralExp *ae, size_t lwr, size_t upr)
+                {
+                    Expressions *w = ae->elements;
+
+                    assert(ae->type->ty == Tsarray ||
+                           ae->type->ty == Tarray);
+                    bool directblk = ((TypeArray *)ae->type)->next->equivalent(newval->type);
+
+                    for (size_t k = lwr; k < upr; k++)
+                    {
+                        if (!directblk && (*w)[k]->op == TOKarrayliteral)
+                        {
+                            // Multidimensional array block assign
+                            if (Expression *ex = assignTo((ArrayLiteralExp *)(*w)[k]))
+                                return ex;
+                        }
+                        else if (refCopy)
+                        {
+                            (*w)[k] = newval;
+                        }
+                        else if (!needsPostblit && !needsDtor)
+                        {
+                            assignInPlace((*w)[k], newval);
+                        }
+                        else
+                        {
+                            Expression *oldelem = (*w)[k];
+                            Expression *tmpelem = needsDtor ? copyLiteral(oldelem).copy() : NULL;
+
+                            assignInPlace(oldelem, newval);
+
+                            if (needsPostblit)
+                            {
+                                if (Expression *ex = evaluatePostblit(istate, oldelem))
+                                    return ex;
+                            }
+                            if (needsDtor)
+                            {
+                                // Bugzilla 14860
+                                if (Expression *ex = evaluateDtor(istate, tmpelem))
+                                    return ex;
+                            }
+                        }
+                    }
+                    return NULL;
+                }
+            };
+
+            Type *tn = newval->type->toBasetype();
+            bool wantRef = (tn->ty == Tarray || isAssocArray(tn) ||tn->ty == Tclass);
+            bool cow = newval->op != TOKstructliteral &&
+                       newval->op != TOKarrayliteral &&
+                       newval->op != TOKstring;
+            Type *tb = tn->baseElemOf();
+            StructDeclaration *sd = (tb->ty == Tstruct ? ((TypeStruct *)tb)->sym : NULL);
+
+            RecursiveBlock rb;
+            rb.istate = istate;
+            rb.newval = newval;
+            rb.refCopy = wantRef || cow;
+            rb.needsPostblit = sd && sd->postblit && e->op != TOKblit && e->e2->isLvalue();
+            rb.needsDtor = sd && sd->dtor && e->op == TOKassign;
+
+            if (Expression *ex = rb.assignTo(existingAE, lowerbound, upperbound))
+                return ex;
+
+            if (goal == ctfeNeedNothing)
+                return NULL; // avoid creating an unused literal
+            SliceExp *retslice = new SliceExp(e->loc, existingAE,
+                new IntegerExp(e->loc, firstIndex, Type::tsize_t),
+                new IntegerExp(e->loc, firstIndex + upperbound - lowerbound, Type::tsize_t));
+            retslice->type = e->type;
+            return interpret(retslice, istate);
+        }
+
+        e->error("slice operation %s = %s cannot be evaluated at compile time",
+            e1->toChars(), newval->toChars());
+        return CTFEExp::cantexp;
+    }
+
+    void visit(AssignExp *e)
+    {
+        interpretAssignCommon(e, NULL);
+    }
+
+    void visit(BinAssignExp *e)
+    {
+        switch (e->op)
+        {
+        case TOKaddass:  interpretAssignCommon(e, &Add);        return;
+        case TOKminass:  interpretAssignCommon(e, &Min);        return;
+        case TOKcatass:  interpretAssignCommon(e, &ctfeCat);    return;
+        case TOKmulass:  interpretAssignCommon(e, &Mul);        return;
+        case TOKdivass:  interpretAssignCommon(e, &Div);        return;
+        case TOKmodass:  interpretAssignCommon(e, &Mod);        return;
+        case TOKshlass:  interpretAssignCommon(e, &Shl);        return;
+        case TOKshrass:  interpretAssignCommon(e, &Shr);        return;
+        case TOKushrass: interpretAssignCommon(e, &Ushr);       return;
+        case TOKandass:  interpretAssignCommon(e, &And);        return;
+        case TOKorass:   interpretAssignCommon(e, &Or);         return;
+        case TOKxorass:  interpretAssignCommon(e, &Xor);        return;
+        case TOKpowass:  interpretAssignCommon(e, &Pow);        return;
+        default:
+            assert(0);
+            return;
+        }
+    }
+
+    void visit(PostExp *e)
+    {
+    #if LOG
+        printf("%s PostExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        if (e->op == TOKplusplus)
+            interpretAssignCommon(e, &Add, 1);
+        else
+            interpretAssignCommon(e, &Min, 1);
+    #if LOG
+        if (CTFEExp::isCantExp(result))
+            printf("PostExp::interpret() CANT\n");
+    #endif
+    }
+
+    /* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison;
+     *       -1 if e is a p1 < p2 or p1 <= p2 pointer comparison;
+     *        0 otherwise
+     */
+    static int isPointerCmpExp(Expression *e, Expression **p1, Expression **p2)
+    {
+        int ret = 1;
+        while (e->op == TOKnot)
+        {
+            ret *= -1;
+            e = ((NotExp *)e)->e1;
+        }
+        switch (e->op)
+        {
+        case TOKlt:
+        case TOKle:
+            ret *= -1;
+            /* fall through */
+        case TOKgt:
+        case TOKge:
+            *p1 = ((BinExp *)e)->e1;
+            *p2 = ((BinExp *)e)->e2;
+            if (!(isPointer((*p1)->type) && isPointer((*p2)->type)))
+                ret = 0;
+            break;
+        default:
+            ret = 0;
+            break;
+        }
+        return ret;
+    }
+
+    /** Negate a relational operator, eg >= becomes <
+     */
+    static TOK reverseRelation(TOK op)
+    {
+        switch (op)
+        {
+            case TOKge: return TOKlt;
+            case TOKgt: return TOKle;
+            case TOKle: return TOKgt;
+            case TOKlt: return TOKge;
+            default:
+                return assert(0), TOKreserved;
+        }
+    }
+
+    /** If this is a four pointer relation, evaluate it, else return NULL.
+     *
+     *  This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2)
+     *  where p1, p2 are expressions yielding pointers to memory block p,
+     *  and q1, q2 are expressions yielding pointers to memory block q.
+     *  This expression is valid even if p and q are independent memory
+     *  blocks and are therefore not normally comparable; the && form returns true
+     *  if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns
+     *  true if [p1..p2] lies outside [q1..q2], and false otherwise.
+     *
+     *  Within the expression, any ordering of p1, p2, q1, q2 is permissible;
+     *  the comparison operators can be any of >, <, <=, >=, provided that
+     *  both directions (p > q and p < q) are checked. Additionally the
+     *  relational sub-expressions can be negated, eg
+     *  (!(q1 < p1) && p2 <= q2) is valid.
+     */
+    void interpretFourPointerRelation(BinExp *e)
+    {
+        assert(e->op == TOKandand || e->op == TOKoror);
+
+        /*  It can only be an isInside expression, if both e1 and e2 are
+         *  directional pointer comparisons.
+         *  Note that this check can be made statically; it does not depends on
+         *  any runtime values. This allows a JIT implementation to compile a
+         *  special AndAndPossiblyInside, keeping the normal AndAnd case efficient.
+         */
+
+        // Save the pointer expressions and the comparison directions,
+        // so we can use them later.
+        Expression *p1 = NULL;
+        Expression *p2 = NULL;
+        Expression *p3 = NULL;
+        Expression *p4 = NULL;
+        int dir1 = isPointerCmpExp(e->e1, &p1, &p2);
+        int dir2 = isPointerCmpExp(e->e2, &p3, &p4);
+        if (dir1 == 0 || dir2 == 0)
+        {
+            result = NULL;
+            return;
+        }
+
+        //printf("FourPointerRelation %s\n", toChars());
+
+        // Evaluate the first two pointers
+        p1 = interpret(p1, istate);
+        if (exceptionOrCant(p1))
+            return;
+        p2 = interpret(p2, istate);
+        if (exceptionOrCant(p2))
+            return;
+        dinteger_t ofs1, ofs2;
+        Expression *agg1 = getAggregateFromPointer(p1, &ofs1);
+        Expression *agg2 = getAggregateFromPointer(p2, &ofs2);
+
+        if (!pointToSameMemoryBlock(agg1, agg2) &&
+            agg1->op != TOKnull &&
+            agg2->op != TOKnull)
+        {
+            // Here it is either CANT_INTERPRET,
+            // or an IsInside comparison returning false.
+            p3 = interpret(p3, istate);
+            if (CTFEExp::isCantExp(p3))
+                return;
+            // Note that it is NOT legal for it to throw an exception!
+            Expression *except = NULL;
+            if (exceptionOrCantInterpret(p3))
+                except = p3;
+            else
+            {
+                p4 = interpret(p4, istate);
+                if (CTFEExp::isCantExp(p4))
+                {
+                    result = p4;
+                    return;
+                }
+                if (exceptionOrCantInterpret(p4))
+                    except = p4;
+            }
+            if (except)
+            {
+                e->error("comparison %s of pointers to unrelated memory blocks remains "
+                     "indeterminate at compile time "
+                     "because exception %s was thrown while evaluating %s",
+                     e->e1->toChars(), except->toChars(), e->e2->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            dinteger_t ofs3, ofs4;
+            Expression *agg3 = getAggregateFromPointer(p3, &ofs3);
+            Expression *agg4 = getAggregateFromPointer(p4, &ofs4);
+            // The valid cases are:
+            // p1 > p2 && p3 > p4  (same direction, also for < && <)
+            // p1 > p2 && p3 < p4  (different direction, also < && >)
+            // Changing any > into >= doesnt affect the result
+            if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) ||
+                (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
+            {
+                // it's a legal two-sided comparison
+                result = new IntegerExp(e->loc, (e->op == TOKandand) ?  0 : 1, e->type);
+                return;
+            }
+            // It's an invalid four-pointer comparison. Either the second
+            // comparison is in the same direction as the first, or else
+            // more than two memory blocks are involved (either two independent
+            // invalid comparisons are present, or else agg3 == agg4).
+            e->error("comparison %s of pointers to unrelated memory blocks is "
+                "indeterminate at compile time, even when combined with %s.",
+                e->e1->toChars(), e->e2->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        // The first pointer expression didn't need special treatment, so we
+        // we need to interpret the entire expression exactly as a normal && or ||.
+        // This is easy because we haven't evaluated e2 at all yet, and we already
+        // know it will return a bool.
+        // But we mustn't evaluate the pointer expressions in e1 again, in case
+        // they have side-effects.
+        bool nott = false;
+        Expression *ex = e->e1;
+        while (ex->op == TOKnot)
+        {
+            nott = !nott;
+            ex = ((NotExp *)ex)->e1;
+        }
+        TOK cmpop = ex->op;
+        if (nott)
+            cmpop = reverseRelation(cmpop);
+        int cmp = comparePointers(e->loc, cmpop, e->e1->type, agg1, ofs1, agg2, ofs2);
+        // We already know this is a valid comparison.
+        assert(cmp >= 0);
+        if (e->op == TOKandand && cmp == 1 ||
+            e->op == TOKoror   && cmp == 0)
+        {
+            result = interpret(e->e2, istate);
+            return;
+        }
+        result = new IntegerExp(e->loc, (e->op == TOKandand) ? 0 : 1, e->type);
+    }
+
+    void visit(AndAndExp *e)
+    {
+    #if LOG
+        printf("%s AndAndExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+
+        // Check for an insidePointer expression, evaluate it if so
+        interpretFourPointerRelation(e);
+        if (result)
+            return;
+
+        result = interpret(e->e1, istate);
+        if (exceptionOrCant(result))
+            return;
+
+        int res;
+        if (result->isBool(false))
+            res = 0;
+        else if (isTrueBool(result))
+        {
+            result = interpret(e->e2, istate);
+            if (exceptionOrCant(result))
+                return;
+            if (result->op == TOKvoidexp)
+            {
+                assert(e->type->ty == Tvoid);
+                result = NULL;
+                return;
+            }
+            if (result->isBool(false))
+                res = 0;
+            else if (isTrueBool(result))
+                res = 1;
+            else
+            {
+                result->error("%s does not evaluate to a boolean", result->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+        }
+        else
+        {
+            result->error("%s cannot be interpreted as a boolean", result->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        if (goal != ctfeNeedNothing)
+            result = new IntegerExp(e->loc, res, e->type);
+    }
+
+    void visit(OrOrExp *e)
+    {
+    #if LOG
+        printf("%s OrOrExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+
+        // Check for an insidePointer expression, evaluate it if so
+        interpretFourPointerRelation(e);
+        if (result)
+            return;
+
+        result = interpret(e->e1, istate);
+        if (exceptionOrCant(result))
+            return;
+
+        int res;
+        if (isTrueBool(result))
+            res = 1;
+        else if (result->isBool(false))
+        {
+            result = interpret(e->e2, istate);
+            if (exceptionOrCant(result))
+                return;
+            if (result->op == TOKvoidexp)
+            {
+                assert(e->type->ty == Tvoid);
+                result = NULL;
+                return;
+            }
+            if (result->isBool(false))
+                res = 0;
+            else if (isTrueBool(result))
+                res = 1;
+            else
+            {
+                result->error("%s cannot be interpreted as a boolean", result->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+        }
+        else
+        {
+            result->error("%s cannot be interpreted as a boolean", result->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        if (goal != ctfeNeedNothing)
+            result = new IntegerExp(e->loc, res, e->type);
+    }
+
+    // Print a stack trace, starting from callingExp which called fd.
+    // To shorten the stack trace, try to detect recursion.
+    void showCtfeBackTrace(CallExp * callingExp, FuncDeclaration *fd)
+    {
+        if (CtfeStatus::stackTraceCallsToSuppress > 0)
+        {
+            --CtfeStatus::stackTraceCallsToSuppress;
+            return;
+        }
+        errorSupplemental(callingExp->loc, "called from here: %s", callingExp->toChars());
+        // Quit if it's not worth trying to compress the stack trace
+        if (CtfeStatus::callDepth < 6 || global.params.verbose)
+            return;
+        // Recursion happens if the current function already exists in the call stack.
+        int numToSuppress = 0;
+        int recurseCount = 0;
+        int depthSoFar = 0;
+        InterState *lastRecurse = istate;
+        for (InterState * cur = istate; cur; cur = cur->caller)
+        {
+            if (cur->fd == fd)
+            {
+                ++recurseCount;
+                numToSuppress = depthSoFar;
+                lastRecurse = cur;
+            }
+            ++depthSoFar;
+        }
+        // We need at least three calls to the same function, to make compression worthwhile
+        if (recurseCount < 2)
+            return;
+        // We found a useful recursion.  Print all the calls involved in the recursion
+        errorSupplemental(fd->loc, "%d recursive calls to function %s", recurseCount, fd->toChars());
+        for (InterState *cur = istate; cur->fd != fd; cur = cur->caller)
+        {
+            errorSupplemental(cur->fd->loc, "recursively called from function %s", cur->fd->toChars());
+        }
+        // We probably didn't enter the recursion in this function.
+        // Go deeper to find the real beginning.
+        InterState * cur = istate;
+        while (lastRecurse->caller && cur->fd == lastRecurse->caller->fd)
+        {
+            cur = cur->caller;
+            lastRecurse = lastRecurse->caller;
+            ++numToSuppress;
+        }
+        CtfeStatus::stackTraceCallsToSuppress = numToSuppress;
+    }
+
+    void visit(CallExp *e)
+    {
+    #if LOG
+        printf("%s CallExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+
+        Expression *pthis = NULL;
+        FuncDeclaration *fd = NULL;
+
+        Expression *ecall = interpret(e->e1, istate);
+        if (exceptionOrCant(ecall))
+            return;
+
+        if (ecall->op == TOKdotvar)
+        {
+            DotVarExp *dve = (DotVarExp *)ecall;
+
+            // Calling a member function
+            pthis = dve->e1;
+            fd = dve->var->isFuncDeclaration();
+            assert(fd);
+
+            if (pthis->op == TOKdottype)
+                pthis = ((DotTypeExp *)dve->e1)->e1;
+        }
+        else if (ecall->op == TOKvar)
+        {
+            fd = ((VarExp *)ecall)->var->isFuncDeclaration();
+            assert(fd);
+
+            if (fd->ident == Id::_ArrayPostblit ||
+                fd->ident == Id::_ArrayDtor)
+            {
+                assert(e->arguments->dim == 1);
+                Expression *ea = (*e->arguments)[0];
+                //printf("1 ea = %s %s\n", ea->type->toChars(), ea->toChars());
+                if (ea->op == TOKslice)
+                    ea = ((SliceExp *)ea)->e1;
+                if (ea->op == TOKcast)
+                    ea = ((CastExp *)ea)->e1;
+
+                //printf("2 ea = %s, %s %s\n", ea->type->toChars(), Token::toChars(ea->op), ea->toChars());
+                if (ea->op == TOKvar || ea->op == TOKsymoff)
+                    result = getVarExp(e->loc, istate, ((SymbolExp *)ea)->var, ctfeNeedRvalue);
+                else if (ea->op == TOKaddress)
+                    result = interpret(((AddrExp *)ea)->e1, istate);
+                else
+                    assert(0);
+                if (CTFEExp::isCantExp(result))
+                    return;
+
+                if (fd->ident == Id::_ArrayPostblit)
+                    result = evaluatePostblit(istate, result);
+                else
+                    result = evaluateDtor(istate, result);
+                if (!result)
+                    result = CTFEExp::voidexp;
+                return;
+            }
+        }
+        else if (ecall->op == TOKsymoff)
+        {
+            SymOffExp *soe = (SymOffExp *)ecall;
+            fd = soe->var->isFuncDeclaration();
+            assert(fd && soe->offset == 0);
+        }
+        else if (ecall->op == TOKdelegate)
+        {
+            // Calling a delegate
+            fd = ((DelegateExp *)ecall)->func;
+            pthis = ((DelegateExp *)ecall)->e1;
+
+            // Special handling for: &nestedfunc --> DelegateExp(VarExp(nestedfunc), nestedfunc)
+            if (pthis->op == TOKvar && ((VarExp *)pthis)->var == fd)
+                pthis = NULL;   // context is not necessary for CTFE
+        }
+        else if (ecall->op == TOKfunction)
+        {
+            // Calling a delegate literal
+            fd = ((FuncExp *)ecall)->fd;
+        }
+        else
+        {
+            // delegate.funcptr()
+            // others
+            e->error("cannot call %s at compile time", e->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        if (!fd)
+        {
+            e->error("CTFE internal error: cannot evaluate %s at compile time", e->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        if (pthis)
+        {
+            // Member function call
+
+            // Currently this is satisfied because closure is not yet supported.
+            assert(!fd->isNested());
+
+            if (pthis->op == TOKtypeid)
+            {
+                pthis->error("static variable %s cannot be read at compile time", pthis->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            assert(pthis);
+
+            if (pthis->op == TOKnull)
+            {
+                assert(pthis->type->toBasetype()->ty == Tclass);
+                e->error("function call through null class reference %s", pthis->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            assert(pthis->op == TOKstructliteral || pthis->op == TOKclassreference);
+
+            if (fd->isVirtual() && !e->directcall)
+            {
+                // Make a virtual function call.
+                // Get the function from the vtable of the original class
+                assert(pthis->op == TOKclassreference);
+                ClassDeclaration *cd = ((ClassReferenceExp *)pthis)->originalClass();
+
+                // We can't just use the vtable index to look it up, because
+                // vtables for interfaces don't get populated until the glue layer.
+                fd = cd->findFunc(fd->ident, (TypeFunction *)fd->type);
+                assert(fd);
+            }
+        }
+
+        if (fd && fd->semanticRun >= PASSsemantic3done && fd->semantic3Errors)
+        {
+            e->error("CTFE failed because of previous errors in %s", fd->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        // Check for built-in functions
+        result = evaluateIfBuiltin(istate, e->loc, fd, e->arguments, pthis);
+        if (result)
+            return;
+
+        if (!fd->fbody)
+        {
+            e->error("%s cannot be interpreted at compile time,"
+                " because it has no available source code", fd->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        result = interpret(fd, istate, e->arguments, pthis);
+        if (result->op == TOKvoidexp)
+            return;
+        if (!exceptionOrCantInterpret(result))
+        {
+            if (goal != ctfeNeedLvalue) // Peel off CTFE reference if it's unnesessary
+                result = interpret(result, istate);
+        }
+        if (!exceptionOrCantInterpret(result))
+        {
+            result = paintTypeOntoLiteral(e->type, result);
+            result->loc = e->loc;
+        }
+        else if (CTFEExp::isCantExp(result) && !global.gag)
+            showCtfeBackTrace(e, fd);   // Print a stack trace.
+    }
+
+    void visit(CommaExp *e)
+    {
+    #if LOG
+        printf("%s CommaExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+
+        CommaExp *firstComma = e;
+        while (firstComma->e1->op == TOKcomma)
+            firstComma = (CommaExp *)firstComma->e1;
+
+        // If it creates a variable, and there's no context for
+        // the variable to be created in, we need to create one now.
+        InterState istateComma;
+        if (!istate && firstComma->e1->op == TOKdeclaration)
+        {
+            ctfeStack.startFrame(NULL);
+            istate = &istateComma;
+        }
+
+        result = CTFEExp::cantexp;
+
+        // If the comma returns a temporary variable, it needs to be an lvalue
+        // (this is particularly important for struct constructors)
+        if (e->e1->op == TOKdeclaration && e->e2->op == TOKvar &&
+            ((DeclarationExp *)e->e1)->declaration == ((VarExp*)e->e2)->var &&
+            ((VarExp*)e->e2)->var->storage_class & STCctfe)  // same as Expression::isTemp
+        {
+            VarExp *ve = (VarExp *)e->e2;
+            VarDeclaration *v = ve->var->isVarDeclaration();
+            ctfeStack.push(v);
+            if (!v->_init && !getValue(v))
+            {
+                setValue(v, copyLiteral(v->type->defaultInitLiteral(e->loc)).copy());
+            }
+            if (!getValue(v))
+            {
+                Expression *newval = initializerToExpression(v->_init);
+                // Bug 4027. Copy constructors are a weird case where the
+                // initializer is a void function (the variable is modified
+                // through a reference parameter instead).
+                newval = interpret(newval, istate);
+                if (exceptionOrCant(newval))
+                    goto Lfin;
+                if (newval->op != TOKvoidexp)
+                {
+                    // v isn't necessarily null.
+                    setValueWithoutChecking(v, copyLiteral(newval).copy());
+                }
+            }
+            result = interpret(e->e2, istate, goal);
+        }
+        else
+        {
+            result = interpret(e->e1, istate, ctfeNeedNothing);
+            if (exceptionOrCant(result))
+                goto Lfin;
+            result = interpret(e->e2, istate, goal);
+        }
+    Lfin:
+        // If we created a temporary stack frame, end it now.
+        if (istate == &istateComma)
+            ctfeStack.endFrame();
+    }
+
+    void visit(CondExp *e)
+    {
+    #if LOG
+        printf("%s CondExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        if (isPointer(e->econd->type))
+        {
+            result = interpret(e->econd, istate);
+            if (exceptionOrCant(result))
+                return;
+            if (result->op != TOKnull)
+                result = new IntegerExp(e->loc, 1, Type::tbool);
+        }
+        else
+            result = interpret(e->econd, istate);
+        if (exceptionOrCant(result))
+            return;
+        if (isTrueBool(result))
+            result = interpret(e->e1, istate, goal);
+        else if (result->isBool(false))
+            result = interpret(e->e2, istate, goal);
+        else
+        {
+            e->error("%s does not evaluate to boolean result at compile time",
+                e->econd->toChars());
+            result = CTFEExp::cantexp;
+        }
+    }
+
+    void visit(ArrayLengthExp *e)
+    {
+    #if LOG
+        printf("%s ArrayLengthExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        Expression *e1 = interpret(e->e1, istate);
+        assert(e1);
+        if (exceptionOrCant(e1))
+            return;
+        if (e1->op != TOKstring &&
+            e1->op != TOKarrayliteral &&
+            e1->op != TOKslice &&
+            e1->op != TOKnull)
+        {
+            e->error("%s cannot be evaluated at compile time", e->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        result = new IntegerExp(e->loc, resolveArrayLength(e1), e->type);
+    }
+
+    void visit(DelegatePtrExp *e)
+    {
+    #if LOG
+        printf("%s DelegatePtrExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        Expression *e1 = interpret(e->e1, istate);
+        assert(e1);
+        if (exceptionOrCant(e1))
+            return;
+        e->error("%s cannot be evaluated at compile time", e->toChars());
+        result = CTFEExp::cantexp;
+    }
+
+    void visit(DelegateFuncptrExp *e)
+    {
+    #if LOG
+        printf("%s DelegateFuncptrExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        Expression *e1 = interpret(e->e1, istate);
+        assert(e1);
+        if (exceptionOrCant(e1))
+            return;
+        e->error("%s cannot be evaluated at compile time", e->toChars());
+        result = CTFEExp::cantexp;
+    }
+
+    static bool resolveIndexing(IndexExp *e, InterState *istate, Expression **pagg, uinteger_t *pidx, bool modify)
+    {
+        assert(e->e1->type->toBasetype()->ty != Taarray);
+
+        if (e->e1->type->toBasetype()->ty == Tpointer)
+        {
+            // Indexing a pointer. Note that there is no $ in this case.
+            Expression *e1 = interpret(e->e1, istate);
+            if (exceptionOrCantInterpret(e1))
+                return false;
+
+            Expression *e2 = interpret(e->e2, istate);
+            if (exceptionOrCantInterpret(e2))
+                return false;
+            sinteger_t indx = e2->toInteger();
+
+            dinteger_t ofs;
+            Expression *agg = getAggregateFromPointer(e1, &ofs);
+
+            if (agg->op == TOKnull)
+            {
+                e->error("cannot index through null pointer %s", e->e1->toChars());
+                return false;
+            }
+            if (agg->op == TOKint64)
+            {
+                e->error("cannot index through invalid pointer %s of value %s",
+                    e->e1->toChars(), e1->toChars());
+                return false;
+            }
+            // Pointer to a non-array variable
+            if (agg->op == TOKsymoff)
+            {
+                e->error("mutable variable %s cannot be %s at compile time, even through a pointer",
+                    (char *)(modify ? "modified" : "read"), ((SymOffExp *)agg)->var->toChars());
+                return false;
+            }
+
+            if (agg->op == TOKarrayliteral || agg->op == TOKstring)
+            {
+                dinteger_t len = resolveArrayLength(agg);
+                if (ofs + indx >= len)
+                {
+                    e->error("pointer index [%lld] exceeds allocated memory block [0..%lld]",
+                        ofs + indx, len);
+                    return false;
+                }
+            }
+            else
+            {
+                if (ofs + indx != 0)
+                {
+                    e->error("pointer index [%lld] lies outside memory block [0..1]",
+                        ofs + indx);
+                    return false;
+                }
+            }
+            *pagg = agg;
+            *pidx = ofs + indx;
+            return true;
+        }
+
+        Expression *e1 = interpret(e->e1, istate);
+        if (exceptionOrCantInterpret(e1))
+            return false;
+        if (e1->op == TOKnull)
+        {
+            e->error("cannot index null array %s", e->e1->toChars());
+            return false;
+        }
+        if (e1->op == TOKvector)
+            e1 = ((VectorExp *)e1)->e1;
+
+        // Set the $ variable, and find the array literal to modify
+        if (e1->op != TOKarrayliteral &&
+            e1->op != TOKstring &&
+            e1->op != TOKslice)
+        {
+            e->error("cannot determine length of %s at compile time",
+                e->e1->toChars());
+            return false;
+        }
+
+        dinteger_t len = resolveArrayLength(e1);
+        if (e->lengthVar)
+        {
+            Expression *dollarExp = new IntegerExp(e->loc, len, Type::tsize_t);
+            ctfeStack.push(e->lengthVar);
+            setValue(e->lengthVar, dollarExp);
+        }
+        Expression *e2 = interpret(e->e2, istate);
+        if (e->lengthVar)
+            ctfeStack.pop(e->lengthVar); // $ is defined only inside []
+        if (exceptionOrCantInterpret(e2))
+            return false;
+        if (e2->op != TOKint64)
+        {
+            e->error("CTFE internal error: non-integral index [%s]", e->e2->toChars());
+            return false;
+        }
+
+        if (e1->op == TOKslice)
+        {
+            // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx']
+            uinteger_t index = e2->toInteger();
+            uinteger_t ilwr = ((SliceExp *)e1)->lwr->toInteger();
+            uinteger_t iupr = ((SliceExp *)e1)->upr->toInteger();
+
+            if (index > iupr - ilwr)
+            {
+                e->error("index %llu exceeds array length %llu", index, iupr - ilwr);
+                return false;
+            }
+            *pagg = ((SliceExp *)e1)->e1;
+            *pidx = index + ilwr;
+        }
+        else
+        {
+            *pagg = e1;
+            *pidx = e2->toInteger();
+            if (len <= *pidx)
+            {
+                e->error("array index %lld is out of bounds [0..%lld]",
+                    *pidx, len);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    void visit(IndexExp *e)
+    {
+    #if LOG
+        printf("%s IndexExp::interpret() %s, goal = %d\n", e->loc.toChars(), e->toChars(), goal);
+    #endif
+        if (e->e1->type->toBasetype()->ty == Tpointer)
+        {
+            Expression *agg;
+            uinteger_t indexToAccess;
+            if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
+            {
+                result = CTFEExp::cantexp;
+                return;
+            }
+            if (agg->op == TOKarrayliteral || agg->op == TOKstring)
+            {
+                if (goal == ctfeNeedLvalue)
+                {
+                    // if we need a reference, IndexExp shouldn't be interpreting
+                    // the expression to a value, it should stay as a reference
+                    result = new IndexExp(e->loc, agg,
+                        new IntegerExp(e->e2->loc, indexToAccess, e->e2->type));
+                    result->type = e->type;
+                    return;
+                }
+                result = ctfeIndex(e->loc, e->type, agg, indexToAccess);
+                return;
+            }
+            else
+            {
+                assert(indexToAccess == 0);
+                result = interpret(agg, istate, goal);
+                if (exceptionOrCant(result))
+                    return;
+                result = paintTypeOntoLiteral(e->type, result);
+                return;
+            }
+        }
+
+        if (e->e1->type->toBasetype()->ty == Taarray)
+        {
+            Expression *e1 = interpret(e->e1, istate);
+            if (exceptionOrCant(e1))
+                return;
+            if (e1->op == TOKnull)
+            {
+                if (goal == ctfeNeedLvalue && e1->type->ty == Taarray && e->modifiable)
+                {
+                    assert(0);  // does not reach here?
+                    return;
+                }
+                e->error("cannot index null array %s", e->e1->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            Expression *e2 = interpret(e->e2, istate);
+            if (exceptionOrCant(e2))
+                return;
+
+            if (goal == ctfeNeedLvalue)
+            {
+                // Pointer or reference of a scalar type
+                if (e1 == e->e1 && e2 == e->e2)
+                    result = e;
+                else
+                {
+                    result = new IndexExp(e->loc, e1, e2);
+                    result->type = e->type;
+                }
+                return;
+            }
+
+            assert(e1->op == TOKassocarrayliteral);
+            e2 = resolveSlice(e2);
+            result = findKeyInAA(e->loc, (AssocArrayLiteralExp *)e1, e2);
+            if (!result)
+            {
+                e->error("key %s not found in associative array %s",
+                    e2->toChars(), e->e1->toChars());
+                result = CTFEExp::cantexp;
+            }
+            return;
+        }
+
+        Expression *agg;
+        uinteger_t indexToAccess;
+        if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
+        {
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        if (goal == ctfeNeedLvalue)
+        {
+            Expression *e2 = new IntegerExp(e->e2->loc, indexToAccess, Type::tsize_t);
+            result = new IndexExp(e->loc, agg, e2);
+            result->type = e->type;
+            return;
+        }
+
+        result = ctfeIndex(e->loc, e->type, agg, indexToAccess);
+        if (exceptionOrCant(result))
+            return;
+        if (result->op == TOKvoid)
+        {
+            e->error("%s is used before initialized", e->toChars());
+            errorSupplemental(result->loc, "originally uninitialized here");
+            result = CTFEExp::cantexp;
+            return;
+        }
+        result = paintTypeOntoLiteral(e->type, result);
+    }
+
+    void visit(SliceExp *e)
+    {
+    #if LOG
+        printf("%s SliceExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+
+        if (e->e1->type->toBasetype()->ty == Tpointer)
+        {
+            // Slicing a pointer. Note that there is no $ in this case.
+            Expression *e1 = interpret(e->e1, istate);
+            if (exceptionOrCant(e1))
+                return;
+            if (e1->op == TOKint64)
+            {
+                e->error("cannot slice invalid pointer %s of value %s",
+                    e->e1->toChars(), e1->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+
+            /* Evaluate lower and upper bounds of slice
+             */
+            Expression *lwr = interpret(e->lwr, istate);
+            if (exceptionOrCant(lwr))
+                return;
+            Expression *upr = interpret(e->upr, istate);
+            if (exceptionOrCant(upr))
+                return;
+            uinteger_t ilwr = lwr->toInteger();
+            uinteger_t iupr = upr->toInteger();
+
+            dinteger_t ofs;
+            Expression *agg = getAggregateFromPointer(e1, &ofs);
+            ilwr += ofs;
+            iupr += ofs;
+            if (agg->op == TOKnull)
+            {
+                if (iupr == ilwr)
+                {
+                    result = new NullExp(e->loc);
+                    result->type = e->type;
+                    return;
+                }
+                e->error("cannot slice null pointer %s", e->e1->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            if (agg->op == TOKsymoff)
+            {
+                e->error("slicing pointers to static variables is not supported in CTFE");
+                result = CTFEExp::cantexp;
+                return;
+            }
+            if (agg->op != TOKarrayliteral && agg->op != TOKstring)
+            {
+                e->error("pointer %s cannot be sliced at compile time (it does not point to an array)",
+                    e->e1->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            assert(agg->op == TOKarrayliteral || agg->op == TOKstring);
+            dinteger_t len = ArrayLength(Type::tsize_t, agg).exp()->toInteger();
+            //Type *pointee = ((TypePointer *)agg->type)->next;
+            if (iupr > (len + 1) || iupr < ilwr)
+            {
+                e->error("pointer slice [%lld..%lld] exceeds allocated memory block [0..%lld]",
+                    ilwr, iupr, len);
+                result = CTFEExp::cantexp;
+                return;
+            }
+            if (ofs != 0)
+            {
+                lwr = new IntegerExp(e->loc, ilwr, lwr->type);
+                upr = new IntegerExp(e->loc, iupr, upr->type);
+            }
+            result = new SliceExp(e->loc, agg, lwr, upr);
+            result->type = e->type;
+            return;
+        }
+
+        Expression *e1 = interpret(e->e1, istate);
+        if (exceptionOrCant(e1))
+            return;
+
+        if (!e->lwr)
+        {
+            result = paintTypeOntoLiteral(e->type, e1);
+            return;
+        }
+
+        /* Set the $ variable
+         */
+        if (e1->op != TOKarrayliteral &&
+            e1->op != TOKstring &&
+            e1->op != TOKnull &&
+            e1->op != TOKslice)
+        {
+            e->error("cannot determine length of %s at compile time", e1->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        uinteger_t dollar = resolveArrayLength(e1);
+        if (e->lengthVar)
+        {
+            IntegerExp *dollarExp = new IntegerExp(e->loc, dollar, Type::tsize_t);
+            ctfeStack.push(e->lengthVar);
+            setValue(e->lengthVar, dollarExp);
+        }
+
+        /* Evaluate lower and upper bounds of slice
+         */
+        Expression *lwr = interpret(e->lwr, istate);
+        if (exceptionOrCant(lwr))
+        {
+            if (e->lengthVar)
+                ctfeStack.pop(e->lengthVar);
+            return;
+        }
+        Expression *upr = interpret(e->upr, istate);
+        if (exceptionOrCant(upr))
+        {
+            if (e->lengthVar)
+                ctfeStack.pop(e->lengthVar);
+            return;
+        }
+        if (e->lengthVar)
+            ctfeStack.pop(e->lengthVar);    // $ is defined only inside [L..U]
+
+        uinteger_t ilwr = lwr->toInteger();
+        uinteger_t iupr = upr->toInteger();
+        if (e1->op == TOKnull)
+        {
+            if (ilwr == 0 && iupr == 0)
+            {
+                result = e1;
+                return;
+            }
+            e1->error("slice [%llu..%llu] is out of bounds", ilwr, iupr);
+            result = CTFEExp::cantexp;
+            return;
+        }
+        if (e1->op == TOKslice)
+        {
+            SliceExp *se = (SliceExp *)e1;
+            // Simplify slice of slice:
+            //  aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
+            uinteger_t lo1 = se->lwr->toInteger();
+            uinteger_t up1 = se->upr->toInteger();
+            if (ilwr > iupr || iupr > up1 - lo1)
+            {
+                e->error("slice[%llu..%llu] exceeds array bounds[%llu..%llu]",
+                    ilwr, iupr, lo1, up1);
+                result = CTFEExp::cantexp;
+                return;
+            }
+            ilwr += lo1;
+            iupr += lo1;
+            result = new SliceExp(e->loc, se->e1,
+                    new IntegerExp(e->loc, ilwr, lwr->type),
+                    new IntegerExp(e->loc, iupr, upr->type));
+            result->type = e->type;
+            return;
+        }
+        if (e1->op == TOKarrayliteral || e1->op == TOKstring)
+        {
+            if (iupr < ilwr || dollar < iupr)
+            {
+                e->error("slice [%lld..%lld] exceeds array bounds [0..%lld]", ilwr, iupr, dollar);
+                result = CTFEExp::cantexp;
+                return;
+            }
+        }
+        result = new SliceExp(e->loc, e1, lwr, upr);
+        result->type = e->type;
+    }
+
+    void visit(InExp *e)
+    {
+    #if LOG
+        printf("%s InExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        Expression *e1 = interpret(e->e1, istate);
+        if (exceptionOrCant(e1))
+            return;
+        Expression *e2 = interpret(e->e2, istate);
+        if (exceptionOrCant(e2))
+            return;
+        if (e2->op == TOKnull)
+        {
+            result = new NullExp(e->loc, e->type);
+            return;
+        }
+        if (e2->op != TOKassocarrayliteral)
+        {
+            e->error("%s cannot be interpreted at compile time", e->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        e1 = resolveSlice(e1);
+        result = findKeyInAA(e->loc, (AssocArrayLiteralExp *)e2, e1);
+        if (exceptionOrCant(result))
+            return;
+        if (!result)
+        {
+            result = new NullExp(e->loc, e->type);
+        }
+        else
+        {
+            // Create a CTFE pointer &aa[index]
+            result = new IndexExp(e->loc, e2, e1);
+            result->type = e->type->nextOf();
+            result = new AddrExp(e->loc, result);
+            result->type = e->type;
+        }
+    }
+
+    void visit(CatExp *e)
+    {
+    #if LOG
+        printf("%s CatExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        Expression *e1 = interpret(e->e1, istate);
+        if (exceptionOrCant(e1))
+            return;
+        Expression *e2 = interpret(e->e2, istate);
+        if (exceptionOrCant(e2))
+            return;
+        e1 = resolveSlice(e1);
+        e2 = resolveSlice(e2);
+        result = ctfeCat(e->type, e1, e2).copy();
+        if (CTFEExp::isCantExp(result))
+        {
+            e->error("%s cannot be interpreted at compile time", e->toChars());
+            return;
+        }
+        // We know we still own it, because we interpreted both e1 and e2
+        if (result->op == TOKarrayliteral)
+            ((ArrayLiteralExp *)result)->ownedByCtfe = OWNEDctfe;
+        if (result->op == TOKstring)
+            ((StringExp *)result)->ownedByCtfe = OWNEDctfe;
+    }
+
+
+    void visit(CastExp *e)
+    {
+    #if LOG
+        printf("%s CastExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        Expression *e1 = interpret(e->e1, istate, goal);
+        if (exceptionOrCant(e1))
+            return;
+        // If the expression has been cast to void, do nothing.
+        if (e->to->ty == Tvoid)
+        {
+            result = CTFEExp::voidexp;
+            return;
+        }
+        if (e->to->ty == Tpointer && e1->op != TOKnull)
+        {
+            Type *pointee = ((TypePointer *)e->type)->next;
+            // Implement special cases of normally-unsafe casts
+            if (e1->op == TOKint64)
+            {
+                // Happens with Windows HANDLEs, for example.
+                result = paintTypeOntoLiteral(e->to, e1);
+                return;
+            }
+            bool castToSarrayPointer = false;
+            bool castBackFromVoid = false;
+            if (e1->type->ty == Tarray || e1->type->ty == Tsarray || e1->type->ty == Tpointer)
+            {
+                // Check for unsupported type painting operations
+                // For slices, we need the type being sliced,
+                // since it may have already been type painted
+                Type *elemtype = e1->type->nextOf();
+                if (e1->op == TOKslice)
+                    elemtype = ((SliceExp *)e1)->e1->type->nextOf();
+                // Allow casts from X* to void *, and X** to void** for any X.
+                // But don't allow cast from X* to void**.
+                // So, we strip all matching * from source and target to find X.
+                // Allow casts to X* from void* only if the 'void' was originally an X;
+                // we check this later on.
+                Type *ultimatePointee = pointee;
+                Type *ultimateSrc = elemtype;
+                while (ultimatePointee->ty == Tpointer && ultimateSrc->ty == Tpointer)
+                {
+                    ultimatePointee = ultimatePointee->nextOf();
+                    ultimateSrc = ultimateSrc->nextOf();
+                }
+                if (ultimatePointee->ty == Tsarray && ultimatePointee->nextOf()->equivalent(ultimateSrc))
+                {
+                    castToSarrayPointer = true;
+                }
+                else if (ultimatePointee->ty != Tvoid && ultimateSrc->ty != Tvoid &&
+                    !isSafePointerCast(elemtype, pointee))
+                {
+                    e->error("reinterpreting cast from %s* to %s* is not supported in CTFE",
+                        elemtype->toChars(), pointee->toChars());
+                    result = CTFEExp::cantexp;
+                    return;
+                }
+                if (ultimateSrc->ty == Tvoid)
+                    castBackFromVoid = true;
+            }
+
+            if (e1->op == TOKslice)
+            {
+                if (((SliceExp *)e1)->e1->op == TOKnull)
+                {
+                    result = paintTypeOntoLiteral(e->type, ((SliceExp *)e1)->e1);
+                    return;
+                }
+                // Create a CTFE pointer &aggregate[1..2]
+                result = new IndexExp(e->loc, ((SliceExp *)e1)->e1, ((SliceExp *)e1)->lwr);
+                result->type = e->type->nextOf();
+                result = new AddrExp(e->loc, result);
+                result->type = e->type;
+                return;
+            }
+            if (e1->op == TOKarrayliteral || e1->op == TOKstring)
+            {
+                // Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
+                result = new IndexExp(e->loc, e1, new IntegerExp(e->loc, 0, Type::tsize_t));
+                result->type = e->type->nextOf();
+                result = new AddrExp(e->loc, result);
+                result->type = e->type;
+                return;
+            }
+            if (e1->op == TOKindex && !((IndexExp *)e1)->e1->type->equals(e1->type))
+            {
+                // type painting operation
+                IndexExp *ie = (IndexExp *)e1;
+                result = new IndexExp(e1->loc, ie->e1, ie->e2);
+                if (castBackFromVoid)
+                {
+                    // get the original type. For strings, it's just the type...
+                    Type *origType = ie->e1->type->nextOf();
+                    // ..but for arrays of type void*, it's the type of the element
+                    Expression *xx = NULL;
+                    if (ie->e1->op == TOKarrayliteral && ie->e2->op == TOKint64)
+                    {
+                        ArrayLiteralExp *ale = (ArrayLiteralExp *)ie->e1;
+                        size_t indx = (size_t)ie->e2->toInteger();
+                        if (indx < ale->elements->dim)
+                            xx = (*ale->elements)[indx];
+                    }
+                    if (xx && xx->op == TOKindex)
+                        origType = ((IndexExp *)xx)->e1->type->nextOf();
+                    else if (xx && xx->op == TOKaddress)
+                        origType= ((AddrExp *)xx)->e1->type;
+                    else if (xx && xx->op == TOKvar)
+                        origType = ((VarExp *)xx)->var->type;
+                    if (!isSafePointerCast(origType, pointee))
+                    {
+                        e->error("using void* to reinterpret cast from %s* to %s* is not supported in CTFE",
+                            origType->toChars(), pointee->toChars());
+                        result = CTFEExp::cantexp;
+                        return;
+                    }
+                }
+                result->type = e->type;
+                return;
+            }
+            if (e1->op == TOKaddress)
+            {
+                Type *origType = ((AddrExp *)e1)->e1->type;
+                if (isSafePointerCast(origType, pointee))
+                {
+                    result = new AddrExp(e->loc, ((AddrExp *)e1)->e1);
+                    result->type = e->type;
+                    return;
+                }
+                if (castToSarrayPointer && pointee->toBasetype()->ty == Tsarray &&
+                    ((AddrExp *)e1)->e1->op == TOKindex)
+                {
+                    // &val[idx]
+                    dinteger_t dim = ((TypeSArray *)pointee->toBasetype())->dim->toInteger();
+                    IndexExp *ie = (IndexExp *)((AddrExp *)e1)->e1;
+                    Expression *lwr = ie->e2;
+                    Expression *upr = new IntegerExp(ie->e2->loc, ie->e2->toInteger() + dim, Type::tsize_t);
+
+                    // Create a CTFE pointer &val[idx..idx+dim]
+                    result = new SliceExp(e->loc, ie->e1, lwr, upr);
+                    result->type = pointee;
+                    result = new AddrExp(e->loc, result);
+                    result->type = e->type;
+                    return;
+                }
+            }
+            if (e1->op == TOKvar || e1->op == TOKsymoff)
+            {
+                // type painting operation
+                Type *origType = ((SymbolExp *)e1)->var->type;
+                if (castBackFromVoid && !isSafePointerCast(origType, pointee))
+                {
+                    e->error("using void* to reinterpret cast from %s* to %s* is not supported in CTFE",
+                        origType->toChars(), pointee->toChars());
+                    result = CTFEExp::cantexp;
+                    return;
+                }
+                if (e1->op == TOKvar)
+                    result = new VarExp(e->loc, ((VarExp *)e1)->var);
+                else
+                    result = new SymOffExp(e->loc, ((SymOffExp *)e1)->var, ((SymOffExp *)e1)->offset);
+                result->type = e->to;
+                return;
+            }
+
+            // Check if we have a null pointer (eg, inside a struct)
+            e1 = interpret(e1, istate);
+            if (e1->op != TOKnull)
+            {
+                e->error("pointer cast from %s to %s is not supported at compile time",
+                    e1->type->toChars(), e->to->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+        }
+        if (e->to->ty == Tsarray && e->e1->type->ty == Tvector)
+        {
+            // Special handling for: cast(float[4])__vector([w, x, y, z])
+            e1 = interpret(e->e1, istate);
+            if (exceptionOrCant(e1))
+                return;
+            assert(e1->op == TOKvector);
+            e1 = ((VectorExp *)e1)->e1;
+        }
+        if (e->to->ty == Tarray && e1->op == TOKslice)
+        {
+            // Note that the slice may be void[], so when checking for dangerous
+            // casts, we need to use the original type, which is se->e1.
+            SliceExp *se = (SliceExp *)e1;
+            if (!isSafePointerCast(se->e1->type->nextOf(), e->to->nextOf()))
+            {
+                e->error("array cast from %s to %s is not supported at compile time",
+                     se->e1->type->toChars(), e->to->toChars());
+                result = CTFEExp::cantexp;
+                return;
+            }
+            e1 = new SliceExp(e1->loc, se->e1, se->lwr, se->upr);
+            e1->type = e->to;
+            result = e1;
+            return;
+        }
+        // Disallow array type painting, except for conversions between built-in
+        // types of identical size.
+        if ((e->to->ty == Tsarray || e->to->ty == Tarray) &&
+            (e1->type->ty == Tsarray || e1->type->ty == Tarray) &&
+            !isSafePointerCast(e1->type->nextOf(), e->to->nextOf()))
+        {
+            e->error("array cast from %s to %s is not supported at compile time", e1->type->toChars(), e->to->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        if (e->to->ty == Tsarray)
+            e1 = resolveSlice(e1);
+        if (e->to->toBasetype()->ty == Tbool && e1->type->ty == Tpointer)
+        {
+            result = new IntegerExp(e->loc, e1->op != TOKnull, e->to);
+            return;
+        }
+        result = ctfeCast(e->loc, e->type, e->to, e1);
+    }
+
+    void visit(AssertExp *e)
+    {
+    #if LOG
+        printf("%s AssertExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        Expression *e1 = interpret(e->e1, istate);
+        if (exceptionOrCant(e1))
+            return;
+        if (isTrueBool(e1))
+        {
+        }
+        else if (e1->isBool(false))
+        {
+            if (e->msg)
+            {
+                result = interpret(e->msg, istate);
+                if (exceptionOrCant(result))
+                    return;
+                e->error("%s", result->toChars());
+            }
+            else
+                e->error("%s failed", e->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        else
+        {
+            e->error("%s is not a compile time boolean expression", e1->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        result = e1;
+        return;
+    }
+
+    void visit(PtrExp *e)
+    {
+    #if LOG
+        printf("%s PtrExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+
+        // Check for int<->float and long<->double casts.
+        if (e->e1->op == TOKsymoff && ((SymOffExp *)e->e1)->offset == 0 &&
+            ((SymOffExp *)e->e1)->var->isVarDeclaration() &&
+            isFloatIntPaint(e->type, ((SymOffExp *)e->e1)->var->type))
+        {
+            // *(cast(int*)&v), where v is a float variable
+            result = paintFloatInt(getVarExp(e->loc, istate, ((SymOffExp *)e->e1)->var, ctfeNeedRvalue), e->type);
+            return;
+        }
+        if (e->e1->op == TOKcast && ((CastExp *)e->e1)->e1->op == TOKaddress)
+        {
+            // *(cast(int*)&x), where x is a float expression
+            Expression *x = ((AddrExp *)(((CastExp *)e->e1)->e1))->e1;
+            if (isFloatIntPaint(e->type, x->type))
+            {
+                result = paintFloatInt(interpret(x, istate), e->type);
+                return;
+            }
+        }
+
+        // Constant fold *(&structliteral + offset)
+        if (e->e1->op == TOKadd)
+        {
+            AddExp *ae = (AddExp *)e->e1;
+            if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
+            {
+                AddrExp *ade = (AddrExp *)ae->e1;
+                Expression *ex = interpret(ade->e1, istate);
+                if (exceptionOrCant(ex))
+                    return;
+                if (ex->op == TOKstructliteral)
+                {
+                    StructLiteralExp *se = (StructLiteralExp *)ex;
+                    dinteger_t offset = ae->e2->toInteger();
+                    result = se->getField(e->type, (unsigned)offset);
+                    if (result)
+                        return;
+                }
+            }
+        }
+
+        // It's possible we have an array bounds error. We need to make sure it
+        // errors with this line number, not the one where the pointer was set.
+        result = interpret(e->e1, istate);
+        if (exceptionOrCant(result))
+            return;
+
+        if (result->op == TOKfunction)
+            return;
+        if (result->op == TOKsymoff)
+        {
+            SymOffExp *soe = (SymOffExp *)result;
+            if (soe->offset == 0 && soe->var->isFuncDeclaration())
+                return;
+            e->error("cannot dereference pointer to static variable %s at compile time", soe->var->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        if (result->op != TOKaddress)
+        {
+            if (result->op == TOKnull)
+                e->error("dereference of null pointer '%s'", e->e1->toChars());
+            else
+                e->error("dereference of invalid pointer '%s'", result->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        // *(&x) ==> x
+        result = ((AddrExp *)result)->e1;
+
+        if (result->op == TOKslice && e->type->toBasetype()->ty == Tsarray)
+        {
+            /* aggr[lwr..upr]
+             * upr may exceed the upper boundary of aggr, but the check is deferred
+             * until those out-of-bounds elements will be touched.
+             */
+            return;
+        }
+        result = interpret(result, istate, goal);
+        if (exceptionOrCant(result))
+            return;
+
+    #if LOG
+        if (CTFEExp::isCantExp(result))
+            printf("PtrExp::interpret() %s = CTFEExp::cantexp\n", e->toChars());
+    #endif
+    }
+
+    void visit(DotVarExp *e)
+    {
+    #if LOG
+        printf("%s DotVarExp::interpret() %s, goal = %d\n", e->loc.toChars(), e->toChars(), goal);
+    #endif
+
+        Expression *ex = interpret(e->e1, istate);
+        if (exceptionOrCant(ex))
+            return;
+
+        if (FuncDeclaration *f = e->var->isFuncDeclaration())
+        {
+            if (ex == e->e1)
+                result = e; // optimize: reuse this CTFE reference
+            else
+            {
+                result = new DotVarExp(e->loc, ex, f, false);
+                result->type = e->type;
+            }
+            return;
+        }
+
+        VarDeclaration *v = e->var->isVarDeclaration();
+        if (!v)
+        {
+            e->error("CTFE internal error: %s", e->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        if (ex->op == TOKnull)
+        {
+            if (ex->type->toBasetype()->ty == Tclass)
+                e->error("class '%s' is null and cannot be dereferenced", e->e1->toChars());
+            else
+                e->error("CTFE internal error: null this '%s'", e->e1->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        if (ex->op != TOKstructliteral && ex->op != TOKclassreference)
+        {
+            e->error("%s.%s is not yet implemented at compile time", e->e1->toChars(), e->var->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        StructLiteralExp *se;
+        int i;
+
+        // We can't use getField, because it makes a copy
+        if (ex->op == TOKclassreference)
+        {
+            se = ((ClassReferenceExp *)ex)->value;
+            i  = ((ClassReferenceExp *)ex)->findFieldIndexByName(v);
+        }
+        else
+        {
+            se = (StructLiteralExp *)ex;
+            i  = findFieldIndexByName(se->sd, v);
+        }
+        if (i == -1)
+        {
+            e->error("couldn't find field %s of type %s in %s", v->toChars(), e->type->toChars(), se->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        if (goal == ctfeNeedLvalue)
+        {
+            Expression *ev = (*se->elements)[i];
+            if (!ev || ev->op == TOKvoid)
+                (*se->elements)[i] = voidInitLiteral(e->type, v).copy();
+            // just return the (simplified) dotvar expression as a CTFE reference
+            if (e->e1 == ex)
+                result = e;
+            else
+            {
+                result = new DotVarExp(e->loc, ex, v);
+                result->type = e->type;
+            }
+            return;
+        }
+
+        result = (*se->elements)[i];
+        if (!result)
+        {
+            e->error("Internal Compiler Error: null field %s", v->toChars());
+            result = CTFEExp::cantexp;
+            return;
+        }
+        if (result->op == TOKvoid)
+        {
+            VoidInitExp *ve = (VoidInitExp *)result;
+            const char *s = ve->var->toChars();
+            if (v->overlapped)
+            {
+                e->error("reinterpretation through overlapped field %s is not allowed in CTFE", s);
+                result = CTFEExp::cantexp;
+                return;
+            }
+            e->error("cannot read uninitialized variable %s in CTFE", s);
+            result = CTFEExp::cantexp;
+            return;
+        }
+
+        if (v->type->ty != result->type->ty && v->type->ty == Tsarray)
+        {
+            // Block assignment from inside struct literals
+            TypeSArray *tsa = (TypeSArray *)v->type;
+            size_t len = (size_t)tsa->dim->toInteger();
+            result = createBlockDuplicatedArrayLiteral(ex->loc, v->type, ex, len);
+            (*se->elements)[i] = result;
+        }
+    #if LOG
+        if (CTFEExp::isCantExp(result))
+            printf("DotVarExp::interpret() %s = CTFEExp::cantexp\n", e->toChars());
+    #endif
+    }
+
+    void visit(RemoveExp *e)
+    {
+    #if LOG
+        printf("%s RemoveExp::interpret() %s\n", e->loc.toChars(), e->toChars());
+    #endif
+        Expression *agg = interpret(e->e1, istate);
+        if (exceptionOrCant(agg))
+            return;
+        Expression *index = interpret(e->e2, istate);
+        if (exceptionOrCant(index))
+            return;
+        if (agg->op == TOKnull)
+        {
+            result = CTFEExp::voidexp;
+            return;
+        }
+        assert(agg->op == TOKassocarrayliteral);
+        AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)agg;
+        Expressions *keysx = aae->keys;
+        Expressions *valuesx = aae->values;
+        size_t removed = 0;
+        for (size_t j = 0; j < valuesx->dim; ++j)
+        {
+            Expression *ekey = (*keysx)[j];
+            int eq = ctfeEqual(e->loc, TOKequal, ekey, index);
+            if (eq)
+                ++removed;
+            else if (removed != 0)
+            {
+                (*keysx)[j - removed] = ekey;
+                (*valuesx)[j - removed] = (*valuesx)[j];
+            }
+        }
+        valuesx->dim = valuesx->dim - removed;
+        keysx->dim = keysx->dim - removed;
+        result = new IntegerExp(e->loc, removed ? 1 : 0, Type::tbool);
+    }
+
+    void visit(ClassReferenceExp *e)
+    {
+        //printf("ClassReferenceExp::interpret() %s\n", e->value->toChars());
+        result = e;
+    }
+
+    void visit(VoidInitExp *e)
+    {
+        e->error("CTFE internal error: trying to read uninitialized variable");
+        assert(0);
+        result = CTFEExp::cantexp;
+    }
+
+    void visit(ThrownExceptionExp *e)
+    {
+        assert(0); // This should never be interpreted
+        result = e;
+    }
+
+};
+
+Expression *interpret(Expression *e, InterState *istate, CtfeGoal goal)
+{
+    if (!e)
+        return NULL;
+    Interpreter v(istate, goal);
+    e->accept(&v);
+    Expression *ex = v.result;
+    assert(goal == ctfeNeedNothing || ex != NULL);
+    return ex;
+}
+
+/***********************************
+ * Interpret the statement.
+ * Returns:
+ *      NULL    continue to next statement
+ *      TOKcantexp      cannot interpret statement at compile time
+ *      !NULL   expression from return statement, or thrown exception
+ */
+
+Expression *interpret(Statement *s, InterState *istate)
+{
+    if (!s)
+        return NULL;
+    Interpreter v(istate, ctfeNeedNothing);
+    s->accept(&v);
+    return v.result;
+}
+
+Expression *scrubArray(Loc loc, Expressions *elems, bool structlit = false);
+
+/* All results destined for use outside of CTFE need to have their CTFE-specific
+ * features removed.
+ * In particular, all slices must be resolved.
+ */
+Expression *scrubReturnValue(Loc loc, Expression *e)
+{
+    if (e->op == TOKclassreference)
+    {
+        StructLiteralExp *se = ((ClassReferenceExp*)e)->value;
+        se->ownedByCtfe = OWNEDcode;
+        if (!(se->stageflags & stageScrub))
+        {
+            int old = se->stageflags;
+            se->stageflags |= stageScrub;
+            if (Expression *ex = scrubArray(loc, se->elements, true))
+                return ex;
+            se->stageflags = old;
+        }
+    }
+    if (e->op == TOKvoid)
+    {
+        error(loc, "uninitialized variable '%s' cannot be returned from CTFE", ((VoidInitExp *)e)->var->toChars());
+        return new ErrorExp();
+    }
+    e = resolveSlice(e);
+    if (e->op == TOKstructliteral)
+    {
+        StructLiteralExp *se = (StructLiteralExp *)e;
+        se->ownedByCtfe = OWNEDcode;
+        if (!(se->stageflags & stageScrub))
+        {
+            int old = se->stageflags;
+            se->stageflags |= stageScrub;
+            if (Expression *ex = scrubArray(loc, se->elements, true))
+                return ex;
+            se->stageflags = old;
+        }
+    }
+    if (e->op == TOKstring)
+    {
+        ((StringExp *)e)->ownedByCtfe = OWNEDcode;
+    }
+    if (e->op == TOKarrayliteral)
+    {
+        ((ArrayLiteralExp *)e)->ownedByCtfe = OWNEDcode;
+        if (Expression *ex = scrubArray(loc, ((ArrayLiteralExp *)e)->elements))
+            return ex;
+    }
+    if (e->op == TOKassocarrayliteral)
+    {
+        AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
+        aae->ownedByCtfe = OWNEDcode;
+        if (Expression *ex = scrubArray(loc, aae->keys))
+            return ex;
+        if (Expression *ex = scrubArray(loc, aae->values))
+            return ex;
+        aae->type = toBuiltinAAType(aae->type);
+    }
+    return e;
+}
+
+// Return true if every element is either void,
+// or is an array literal or struct literal of void elements.
+bool isEntirelyVoid(Expressions *elems)
+{
+    for (size_t i = 0; i < elems->dim; i++)
+    {
+        Expression *m = (*elems)[i];
+        // It can be NULL for performance reasons,
+        // see StructLiteralExp::interpret().
+        if (!m)
+            continue;
+
+        if (!(m->op == TOKvoid) &&
+            !(m->op == TOKarrayliteral && isEntirelyVoid(((ArrayLiteralExp *)m)->elements)) &&
+            !(m->op == TOKstructliteral && isEntirelyVoid(((StructLiteralExp *)m)->elements)))
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+// Scrub all members of an array. Return false if error
+Expression *scrubArray(Loc loc, Expressions *elems, bool structlit)
+{
+    for (size_t i = 0; i < elems->dim; i++)
+    {
+        Expression *m = (*elems)[i];
+        // It can be NULL for performance reasons,
+        // see StructLiteralExp::interpret().
+        if (!m)
+            continue;
+
+        // A struct .init may contain void members.
+        // Static array members are a weird special case (bug 10994).
+        if (structlit &&
+            ((m->op == TOKvoid) ||
+             (m->op == TOKarrayliteral && m->type->ty == Tsarray && isEntirelyVoid(((ArrayLiteralExp *)m)->elements)) ||
+             (m->op == TOKstructliteral && isEntirelyVoid(((StructLiteralExp *)m)->elements))))
+        {
+                m = NULL;
+        }
+        else
+        {
+            m = scrubReturnValue(loc, m);
+            if (CTFEExp::isCantExp(m) || m->op == TOKerror)
+                return m;
+        }
+        (*elems)[i] = m;
+    }
+    return NULL;
+}
+
+Expression *scrubArrayCache(Loc loc, Expressions *elems);
+
+Expression *scrubCacheValue(Loc loc, Expression *e)
+{
+    if (e->op == TOKclassreference)
+    {
+        StructLiteralExp *sle = ((ClassReferenceExp*)e)->value;
+        sle->ownedByCtfe = OWNEDcache;
+        if (!(sle->stageflags & stageScrub))
+        {
+            int old = sle->stageflags;
+            sle->stageflags |= stageScrub;
+            if (Expression *ex = scrubArrayCache(loc, sle->elements))
+                return ex;
+            sle->stageflags = old;
+        }
+    }
+    if (e->op == TOKstructliteral)
+    {
+        StructLiteralExp *sle = (StructLiteralExp *)e;
+        sle->ownedByCtfe = OWNEDcache;
+        if (!(sle->stageflags & stageScrub))
+        {
+            int old = sle->stageflags;
+            sle->stageflags |= stageScrub;
+            if (Expression *ex = scrubArrayCache(loc, sle->elements))
+                return ex;
+            sle->stageflags = old;
+        }
+    }
+    if (e->op == TOKstring)
+    {
+        ((StringExp *)e)->ownedByCtfe = OWNEDcache;
+    }
+    if (e->op == TOKarrayliteral)
+    {
+        ((ArrayLiteralExp *)e)->ownedByCtfe = OWNEDcache;
+        if (Expression *ex = scrubArrayCache(loc, ((ArrayLiteralExp *)e)->elements))
+            return ex;
+    }
+    if (e->op == TOKassocarrayliteral)
+    {
+        AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
+        aae->ownedByCtfe = OWNEDcache;
+        if (Expression *ex = scrubArrayCache(loc, aae->keys))
+            return ex;
+        if (Expression *ex = scrubArrayCache(loc, aae->values))
+            return ex;
+    }
+    return e;
+}
+
+Expression *scrubArrayCache(Loc loc, Expressions *elems)
+{
+    for (size_t i = 0; i < elems->dim; i++)
+    {
+        Expression *m = (*elems)[i];
+        if (!m)
+            continue;
+        (*elems)[i] = scrubCacheValue(loc, m);
+    }
+    return NULL;
+}
+
+/******************************* Special Functions ***************************/
+
+Expression *interpret_length(InterState *istate, Expression *earg)
+{
+    //printf("interpret_length()\n");
+    earg = interpret(earg, istate);
+    if (exceptionOrCantInterpret(earg))
+        return earg;
+    dinteger_t len = 0;
+    if (earg->op == TOKassocarrayliteral)
+        len = ((AssocArrayLiteralExp *)earg)->keys->dim;
+    else
+        assert(earg->op == TOKnull);
+    Expression *e = new IntegerExp(earg->loc, len, Type::tsize_t);
+    return e;
+}
+
+Expression *interpret_keys(InterState *istate, Expression *earg, Type *returnType)
+{
+#if LOG
+    printf("interpret_keys()\n");
+#endif
+    earg = interpret(earg, istate);
+    if (exceptionOrCantInterpret(earg))
+        return earg;
+    if (earg->op == TOKnull)
+        return new NullExp(earg->loc, returnType);
+    if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
+        return NULL;
+    assert(earg->op == TOKassocarrayliteral);
+    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
+    ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, aae->keys);
+    ae->ownedByCtfe = aae->ownedByCtfe;
+    ae->type = returnType;
+    return copyLiteral(ae).copy();
+}
+
+Expression *interpret_values(InterState *istate, Expression *earg, Type *returnType)
+{
+#if LOG
+    printf("interpret_values()\n");
+#endif
+    earg = interpret(earg, istate);
+    if (exceptionOrCantInterpret(earg))
+        return earg;
+    if (earg->op == TOKnull)
+        return new NullExp(earg->loc, returnType);
+    if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
+        return NULL;
+    assert(earg->op == TOKassocarrayliteral);
+    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
+    ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, aae->values);
+    ae->ownedByCtfe = aae->ownedByCtfe;
+    ae->type = returnType;
+    //printf("result is %s\n", e->toChars());
+    return copyLiteral(ae).copy();
+}
+
+Expression *interpret_dup(InterState *istate, Expression *earg)
+{
+#if LOG
+    printf("interpret_dup()\n");
+#endif
+    earg = interpret(earg, istate);
+    if (exceptionOrCantInterpret(earg))
+        return earg;
+    if (earg->op == TOKnull)
+        return new NullExp(earg->loc, earg->type);
+    if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
+        return NULL;
+    assert(earg->op == TOKassocarrayliteral);
+    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)copyLiteral(earg).copy();
+    for (size_t i = 0; i < aae->keys->dim; i++)
+    {
+        if (Expression *e = evaluatePostblit(istate, (*aae->keys)[i]))
+            return e;
+        if (Expression *e = evaluatePostblit(istate, (*aae->values)[i]))
+            return e;
+    }
+    aae->type = earg->type->mutableOf(); // repaint type from const(int[int]) to const(int)[int]
+    //printf("result is %s\n", aae->toChars());
+    return aae;
+}
+
+// signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
+Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *deleg)
+{
+    aa = interpret(aa, istate);
+    if (exceptionOrCantInterpret(aa))
+        return aa;
+    if (aa->op != TOKassocarrayliteral)
+        return new IntegerExp(deleg->loc, 0, Type::tsize_t);
+
+    FuncDeclaration *fd = NULL;
+    Expression *pthis = NULL;
+    if (deleg->op == TOKdelegate)
+    {
+        fd = ((DelegateExp *)deleg)->func;
+        pthis = ((DelegateExp *)deleg)->e1;
+    }
+    else if (deleg->op == TOKfunction)
+        fd = ((FuncExp*)deleg)->fd;
+
+    assert(fd && fd->fbody);
+    assert(fd->parameters);
+    size_t numParams = fd->parameters->dim;
+    assert(numParams == 1 || numParams == 2);
+
+    Parameter *fparam = Parameter::getNth(((TypeFunction *)fd->type)->parameters, numParams - 1);
+    bool wantRefValue = 0 != (fparam->storageClass & (STCout | STCref));
+
+    Expressions args;
+    args.setDim(numParams);
+
+    AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)aa;
+    if (!ae->keys || ae->keys->dim == 0)
+        return new IntegerExp(deleg->loc, 0, Type::tsize_t);
+    Expression *eresult;
+
+    for (size_t i = 0; i < ae->keys->dim; ++i)
+    {
+        Expression *ekey = (*ae->keys)[i];
+        Expression *evalue = (*ae->values)[i];
+        if (wantRefValue)
+        {
+            Type *t = evalue->type;
+            evalue = new IndexExp(deleg->loc, ae, ekey);
+            evalue->type = t;
+        }
+        args[numParams - 1] = evalue;
+        if (numParams == 2) args[0] = ekey;
+
+        eresult = interpret(fd, istate, &args, pthis);
+        if (exceptionOrCantInterpret(eresult))
+            return eresult;
+
+        assert(eresult->op == TOKint64);
+        if (((IntegerExp *)eresult)->getInteger() != 0)
+            return eresult;
+    }
+    return eresult;
+}
+
+// Helper function: given a function of type A[] f(...),
+// return A[].
+Type *returnedArrayType(FuncDeclaration *fd)
+{
+    assert(fd->type->ty == Tfunction);
+    assert(fd->type->nextOf()->ty == Tarray);
+    return ((TypeFunction *)fd->type)->nextOf();
+}
+
+/* Decoding UTF strings for foreach loops. Duplicates the functionality of
+ * the twelve _aApplyXXn functions in aApply.d in the runtime.
+ */
+Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *deleg, bool rvs)
+{
+#if LOG
+    printf("foreachApplyUtf(%s, %s)\n", str->toChars(), deleg->toChars());
+#endif
+    FuncDeclaration *fd = NULL;
+    Expression *pthis = NULL;
+    if (deleg->op == TOKdelegate)
+    {
+        fd = ((DelegateExp *)deleg)->func;
+        pthis = ((DelegateExp *)deleg)->e1;
+    }
+    else if (deleg->op == TOKfunction)
+        fd = ((FuncExp*)deleg)->fd;
+
+    assert(fd && fd->fbody);
+    assert(fd->parameters);
+    size_t numParams = fd->parameters->dim;
+    assert(numParams == 1 || numParams == 2);
+    Type *charType = (*fd->parameters)[numParams-1]->type;
+    Type *indexType = numParams == 2 ? (*fd->parameters)[0]->type
+                                     : Type::tsize_t;
+    size_t len = (size_t)resolveArrayLength(str);
+    if (len == 0)
+        return new IntegerExp(deleg->loc, 0, indexType);
+
+    str = resolveSlice(str);
+
+    StringExp *se = NULL;
+    ArrayLiteralExp *ale = NULL;
+    if (str->op == TOKstring)
+        se = (StringExp *) str;
+    else if (str->op == TOKarrayliteral)
+        ale = (ArrayLiteralExp *)str;
+    else
+    {
+        str->error("CTFE internal error: cannot foreach %s", str->toChars());
+        return CTFEExp::cantexp;
+    }
+    Expressions args;
+    args.setDim(numParams);
+
+    Expression *eresult = NULL;         // ded-store to prevent spurious warning
+
+    // Buffers for encoding; also used for decoding array literals
+    utf8_t utf8buf[4];
+    unsigned short utf16buf[2];
+
+    size_t start = rvs ? len : 0;
+    size_t end = rvs ? 0: len;
+    for (size_t indx = start; indx != end;)
+    {
+        // Step 1: Decode the next dchar from the string.
+
+        const char *errmsg = NULL; // Used for reporting decoding errors
+        dchar_t rawvalue;   // Holds the decoded dchar
+        size_t currentIndex = indx; // The index of the decoded character
+
+        if (ale)
+        {
+            // If it is an array literal, copy the code points into the buffer
+            size_t buflen = 1; // #code points in the buffer
+            size_t n = 1;   // #code points in this char
+            size_t sz = (size_t)ale->type->nextOf()->size();
+
+            switch (sz)
+            {
+            case 1:
+                if (rvs)
+                {
+                    // find the start of the string
+                    --indx;
+                    buflen = 1;
+                    while (indx > 0 && buflen < 4)
+                    {
+                        Expression * r = (*ale->elements)[indx];
+                        assert(r->op == TOKint64);
+                        utf8_t x = (utf8_t)(((IntegerExp *)r)->getInteger());
+                        if ((x & 0xC0) != 0x80)
+                            break;
+                        ++buflen;
+                    }
+                }
+                else
+                    buflen = (indx + 4 > len) ? len - indx : 4;
+                for (size_t i = 0; i < buflen; ++i)
+                {
+                    Expression * r = (*ale->elements)[indx + i];
+                    assert(r->op == TOKint64);
+                    utf8buf[i] = (utf8_t)(((IntegerExp *)r)->getInteger());
+                }
+                n = 0;
+                errmsg = utf_decodeChar(&utf8buf[0], buflen, &n, &rawvalue);
+                break;
+            case 2:
+                if (rvs)
+                {
+                    // find the start of the string
+                    --indx;
+                    buflen = 1;
+                    Expression * r = (*ale->elements)[indx];
+                    assert(r->op == TOKint64);
+                    unsigned short x = (unsigned short)(((IntegerExp *)r)->getInteger());
+                    if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
+                    {
+                        --indx;
+                        ++buflen;
+                    }
+                }
+                else
+                    buflen = (indx + 2 > len) ? len - indx : 2;
+                for (size_t i=0; i < buflen; ++i)
+                {
+                    Expression * r = (*ale->elements)[indx + i];
+                    assert(r->op == TOKint64);
+                    utf16buf[i] = (unsigned short)(((IntegerExp *)r)->getInteger());
+                }
+                n = 0;
+                errmsg = utf_decodeWchar(&utf16buf[0], buflen, &n, &rawvalue);
+                break;
+            case 4:
+                {
+                    if (rvs)
+                        --indx;
+
+                    Expression * r = (*ale->elements)[indx];
+                    assert(r->op == TOKint64);
+                    rawvalue = (dchar_t)((IntegerExp *)r)->getInteger();
+                    n = 1;
+                }
+                break;
+            default:
+                assert(0);
+            }
+            if (!rvs)
+                indx += n;
+        }
+        else
+        {
+            // String literals
+            size_t saveindx; // used for reverse iteration
+
+            switch (se->sz)
+            {
+            case 1:
+                if (rvs)
+                {
+                    // find the start of the string
+                    utf8_t *s = (utf8_t *)se->string;
+                    --indx;
+                    while (indx > 0 && ((s[indx]&0xC0) == 0x80))
+                        --indx;
+                    saveindx = indx;
+                }
+                errmsg = utf_decodeChar((utf8_t *)se->string, se->len, &indx, &rawvalue);
+                if (rvs)
+                    indx = saveindx;
+                break;
+            case 2:
+                if (rvs)
+                {
+                    // find the start
+                    unsigned short *s = (unsigned short *)se->string;
+                    --indx;
+                    if (s[indx] >= 0xDC00 && s[indx]<= 0xDFFF)
+                        --indx;
+                    saveindx = indx;
+                }
+                errmsg = utf_decodeWchar((unsigned short *)se->string, se->len, &indx, &rawvalue);
+                if (rvs)
+                    indx = saveindx;
+                break;
+            case 4:
+                if (rvs)
+                    --indx;
+                rawvalue = ((unsigned *)(se->string))[indx];
+                if (!rvs)
+                    ++indx;
+                break;
+            default:
+                assert(0);
+            }
+        }
+        if (errmsg)
+        {
+            deleg->error("%s", errmsg);
+            return CTFEExp::cantexp;
+        }
+
+        // Step 2: encode the dchar in the target encoding
+
+        int charlen = 1; // How many codepoints are involved?
+        switch (charType->size())
+        {
+            case 1:
+                charlen = utf_codeLengthChar(rawvalue);
+                utf_encodeChar(&utf8buf[0], rawvalue);
+                break;
+            case 2:
+                charlen = utf_codeLengthWchar(rawvalue);
+                utf_encodeWchar(&utf16buf[0], rawvalue);
+                break;
+            case 4:
+                break;
+            default:
+                assert(0);
+        }
+        if (rvs)
+            currentIndex = indx;
+
+        // Step 3: call the delegate once for each code point
+
+        // The index only needs to be set once
+        if (numParams == 2)
+            args[0] = new IntegerExp(deleg->loc, currentIndex, indexType);
+
+        Expression *val = NULL;
+
+        for (int k= 0; k < charlen; ++k)
+        {
+            dchar_t codepoint;
+            switch (charType->size())
+            {
+                case 1:
+                    codepoint = utf8buf[k];
+                    break;
+                case 2:
+                    codepoint = utf16buf[k];
+                    break;
+                case 4:
+                    codepoint = rawvalue;
+                    break;
+                default:
+                    assert(0);
+            }
+            val = new IntegerExp(str->loc, codepoint, charType);
+
+            args[numParams - 1] = val;
+
+            eresult = interpret(fd, istate, &args, pthis);
+            if (exceptionOrCantInterpret(eresult))
+                return eresult;
+            assert(eresult->op == TOKint64);
+            if (((IntegerExp *)eresult)->getInteger() != 0)
+                return eresult;
+        }
+    }
+    return eresult;
+}
+
+/* If this is a built-in function, return the interpreted result,
+ * Otherwise, return NULL.
+ */
+Expression *evaluateIfBuiltin(InterState *istate, Loc loc,
+    FuncDeclaration *fd, Expressions *arguments, Expression *pthis)
+{
+    Expression *e = NULL;
+    size_t nargs = arguments ? arguments->dim : 0;
+    if (!pthis)
+    {
+        if (isBuiltin(fd) == BUILTINyes)
+        {
+            Expressions args;
+            args.setDim(nargs);
+            for (size_t i = 0; i < args.dim; i++)
+            {
+                Expression *earg = (*arguments)[i];
+                earg = interpret(earg, istate);
+                if (exceptionOrCantInterpret(earg))
+                    return earg;
+                args[i] = earg;
+            }
+            e = eval_builtin(loc, fd, &args);
+            if (!e)
+            {
+                error(loc, "cannot evaluate unimplemented builtin %s at compile time", fd->toChars());
+                e = CTFEExp::cantexp;
+            }
+        }
+    }
+    if (!pthis)
+    {
+        Expression *firstarg =  nargs > 0 ? (*arguments)[0] : NULL;
+        if (firstarg && firstarg->type->toBasetype()->ty == Taarray)
+        {
+            TypeAArray *firstAAtype = (TypeAArray *)firstarg->type;
+            const char *id = fd->ident->toChars();
+            if (nargs == 1 && fd->ident == Id::aaLen)
+                return interpret_length(istate, firstarg);
+            if (nargs == 3 && !strcmp(id, "_aaApply"))
+                return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2]));
+            if (nargs == 3 && !strcmp(id, "_aaApply2"))
+                return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2]));
+            if (nargs == 1 && !strcmp(id, "keys") && !strcmp(fd->toParent2()->ident->toChars(), "object"))
+                return interpret_keys(istate, firstarg, firstAAtype->index->arrayOf());
+            if (nargs == 1 && !strcmp(id, "values") && !strcmp(fd->toParent2()->ident->toChars(), "object"))
+                return interpret_values(istate, firstarg, firstAAtype->nextOf()->arrayOf());
+            if (nargs == 1 && !strcmp(id, "rehash") && !strcmp(fd->toParent2()->ident->toChars(), "object"))
+                return interpret(firstarg, istate);
+            if (nargs == 1 && !strcmp(id, "dup") && !strcmp(fd->toParent2()->ident->toChars(), "object"))
+                return interpret_dup(istate, firstarg);
+        }
+    }
+    if (pthis && !fd->fbody && fd->isCtorDeclaration() && fd->parent && fd->parent->parent && fd->parent->parent->ident == Id::object)
+    {
+        if (pthis->op == TOKclassreference && fd->parent->ident == Id::Throwable)
+        {
+            // At present, the constructors just copy their arguments into the struct.
+            // But we might need some magic if stack tracing gets added to druntime.
+            StructLiteralExp *se = ((ClassReferenceExp *)pthis)->value;
+            assert(arguments->dim <= se->elements->dim);
+            for (size_t i = 0; i < arguments->dim; ++i)
+            {
+                e = interpret((*arguments)[i], istate);
+                if (exceptionOrCantInterpret(e))
+                    return e;
+                (*se->elements)[i] = e;
+            }
+            return CTFEExp::voidexp;
+        }
+    }
+    if (nargs == 1 && !pthis &&
+        (fd->ident == Id::criticalenter || fd->ident == Id::criticalexit))
+    {
+        // Support synchronized{} as a no-op
+        return CTFEExp::voidexp;
+    }
+    if (!pthis)
+    {
+        const char *id = fd->ident->toChars();
+        size_t idlen = strlen(id);
+        if (nargs == 2 && (idlen == 10 || idlen == 11) &&
+            !strncmp(id, "_aApply", 7))
+        {
+            // Functions from aApply.d and aApplyR.d in the runtime
+            bool rvs = (idlen == 11);   // true if foreach_reverse
+            char c = id[idlen-3]; // char width: 'c', 'w', or 'd'
+            char s = id[idlen-2]; // string width: 'c', 'w', or 'd'
+            char n = id[idlen-1]; // numParams: 1 or 2.
+            // There are 12 combinations
+            if ((n == '1' || n == '2') &&
+                (c == 'c' || c == 'w' || c == 'd') &&
+                (s == 'c' || s == 'w' || s == 'd') && c != s)
+            {
+                Expression *str = (*arguments)[0];
+                str = interpret(str, istate);
+                if (exceptionOrCantInterpret(str))
+                    return str;
+                return foreachApplyUtf(istate, str, (*arguments)[1], rvs);
+            }
+        }
+    }
+    return e;
+}
+
+Expression *evaluatePostblit(InterState *istate, Expression *e)
+{
+    Type *tb = e->type->baseElemOf();
+    if (tb->ty != Tstruct)
+        return NULL;
+    StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+    if (!sd->postblit)
+        return NULL;
+
+    if (e->op == TOKarrayliteral)
+    {
+        ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
+        for (size_t i = 0; i < ale->elements->dim; i++)
+        {
+            e = evaluatePostblit(istate, (*ale->elements)[i]);
+            if (e)
+                return e;
+        }
+        return NULL;
+    }
+    if (e->op == TOKstructliteral)
+    {
+        // e.__postblit()
+        e = interpret(sd->postblit, istate, NULL, e);
+        if (exceptionOrCantInterpret(e))
+            return e;
+        return NULL;
+    }
+    assert(0);
+    return NULL;
+}
+
+Expression *evaluateDtor(InterState *istate, Expression *e)
+{
+    Type *tb = e->type->baseElemOf();
+    if (tb->ty != Tstruct)
+        return NULL;
+    StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+    if (!sd->dtor)
+        return NULL;
+
+    if (e->op == TOKarrayliteral)
+    {
+        ArrayLiteralExp *alex = (ArrayLiteralExp *)e;
+        for (size_t i = alex->elements->dim; 0 < i--; )
+            e = evaluateDtor(istate, (*alex->elements)[i]);
+    }
+    else if (e->op == TOKstructliteral)
+    {
+        // e.__dtor()
+        e = interpret(sd->dtor, istate, NULL, e);
+    }
+    else
+        assert(0);
+    if (exceptionOrCantInterpret(e))
+        return e;
+    return NULL;
+}
+
+/*************************** CTFE Sanity Checks ***************************/
+
+/* Setter functions for CTFE variable values.
+ * These functions exist to check for compiler CTFE bugs.
+ */
+bool hasValue(VarDeclaration *vd)
+{
+    if (vd->ctfeAdrOnStack == (size_t)-1)
+        return false;
+    return NULL != getValue(vd);
+}
+
+Expression *getValue(VarDeclaration *vd)
+{
+    return ctfeStack.getValue(vd);
+}
+
+void setValueNull(VarDeclaration *vd)
+{
+    ctfeStack.setValue(vd, NULL);
+}
+
+// Don't check for validity
+void setValueWithoutChecking(VarDeclaration *vd, Expression *newval)
+{
+    ctfeStack.setValue(vd, newval);
+}
+
+void setValue(VarDeclaration *vd, Expression *newval)
+{
+#if 0
+    if (! ((vd->storage_class & (STCout | STCref))
+            ? isCtfeReferenceValid(newval)
+            : isCtfeValueValid(newval)) )
+    {
+        printf("[%s] vd = %s %s, newval = %s\n", vd->loc.toChars(), vd->type->toChars(), vd->toChars(), newval->toChars());
+    }
+#endif
+    assert((vd->storage_class & (STCout | STCref))
+            ? isCtfeReferenceValid(newval)
+            : isCtfeValueValid(newval));
+    ctfeStack.setValue(vd, newval);
+}
diff --git a/gcc/d/dfrontend/dmacro.c b/gcc/d/dfrontend/dmacro.c
new file mode 100644
index 00000000000..3515fd9ddb7
--- /dev/null
+++ b/gcc/d/dfrontend/dmacro.c
@@ -0,0 +1,468 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2015 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/macro.c
+ */
+
+/* Simple macro text processor.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "errors.h"
+#include "rmem.h"
+#include "root.h"
+
+#include "macro.h"
+
+bool isIdStart(const utf8_t *p);
+bool isIdTail(const utf8_t *p);
+int utfStride(const utf8_t *p);
+
+utf8_t *memdup(const utf8_t *p, size_t len)
+{
+    return (utf8_t *)memcpy(mem.xmalloc(len), p, len);
+}
+
+Macro::Macro(const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen)
+{
+    next = NULL;
+
+    this->name = name;
+    this->namelen = namelen;
+
+    this->text = text;
+    this->textlen = textlen;
+    inuse = 0;
+}
+
+
+Macro *Macro::search(const utf8_t *name, size_t namelen)
+{   Macro *table;
+
+    //printf("Macro::search(%.*s)\n", namelen, name);
+    for (table = this; table; table = table->next)
+    {
+        if (table->namelen == namelen &&
+            memcmp(table->name, name, namelen) == 0)
+        {
+            //printf("\tfound %d\n", table->textlen);
+            break;
+        }
+    }
+    return table;
+}
+
+Macro *Macro::define(Macro **ptable, const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen)
+{
+    //printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text);
+
+    Macro *table;
+
+    //assert(ptable);
+    for (table = *ptable; table; table = table->next)
+    {
+        if (table->namelen == namelen &&
+            memcmp(table->name, name, namelen) == 0)
+        {
+            table->text = text;
+            table->textlen = textlen;
+            return table;
+        }
+    }
+    table = new Macro(name, namelen, text, textlen);
+    table->next = *ptable;
+    *ptable = table;
+    return table;
+}
+
+/**********************************************************
+ * Given buffer p[0..end], extract argument marg[0..marglen].
+ * Params:
+ *      n       0:      get entire argument
+ *              1..9:   get nth argument
+ *              -1:     get 2nd through end
+ */
+
+size_t extractArgN(const utf8_t *p, size_t end, const utf8_t **pmarg, size_t *pmarglen, int n)
+{
+    /* Scan forward for matching right parenthesis.
+     * Nest parentheses.
+     * Skip over "..." and '...' strings inside HTML tags.
+     * Skip over <!-- ... --> comments.
+     * Skip over previous macro insertions
+     * Set marglen.
+     */
+    unsigned parens = 1;
+    unsigned char instring = 0;
+    unsigned incomment = 0;
+    unsigned intag = 0;
+    unsigned inexp = 0;
+    unsigned argn = 0;
+
+    size_t v = 0;
+
+  Largstart:
+    // Skip first space, if any, to find the start of the macro argument
+    if (n != 1 && v < end && isspace(p[v]))
+        v++;
+    *pmarg = p + v;
+
+    for (; v < end; v++)
+    {   utf8_t c = p[v];
+
+        switch (c)
+        {
+            case ',':
+                if (!inexp && !instring && !incomment && parens == 1)
+                {
+                    argn++;
+                    if (argn == 1 && n == -1)
+                    {   v++;
+                        goto Largstart;
+                    }
+                    if (argn == n)
+                        break;
+                    if (argn + 1 == n)
+                    {   v++;
+                        goto Largstart;
+                    }
+                }
+                continue;
+
+            case '(':
+                if (!inexp && !instring && !incomment)
+                    parens++;
+                continue;
+
+            case ')':
+                if (!inexp && !instring && !incomment && --parens == 0)
+                {
+                    break;
+                }
+                continue;
+
+            case '"':
+            case '\'':
+                if (!inexp && !incomment && intag)
+                {
+                    if (c == instring)
+                        instring = 0;
+                    else if (!instring)
+                        instring = c;
+                }
+                continue;
+
+            case '<':
+                if (!inexp && !instring && !incomment)
+                {
+                    if (v + 6 < end &&
+                        p[v + 1] == '!' &&
+                        p[v + 2] == '-' &&
+                        p[v + 3] == '-')
+                    {
+                        incomment = 1;
+                        v += 3;
+                    }
+                    else if (v + 2 < end &&
+                        isalpha(p[v + 1]))
+                        intag = 1;
+                }
+                continue;
+
+            case '>':
+                if (!inexp)
+                    intag = 0;
+                continue;
+
+            case '-':
+                if (!inexp &&
+                    !instring &&
+                    incomment &&
+                    v + 2 < end &&
+                    p[v + 1] == '-' &&
+                    p[v + 2] == '>')
+                {
+                    incomment = 0;
+                    v += 2;
+                }
+                continue;
+
+            case 0xFF:
+                if (v + 1 < end)
+                {
+                    if (p[v + 1] == '{')
+                        inexp++;
+                    else if (p[v + 1] == '}')
+                        inexp--;
+                }
+                continue;
+
+            default:
+                continue;
+        }
+        break;
+    }
+    if (argn == 0 && n == -1)
+        *pmarg = p + v;
+    *pmarglen = p + v - *pmarg;
+    //printf("extractArg%d('%.*s') = '%.*s'\n", n, end, p, *pmarglen, *pmarg);
+    return v;
+}
+
+
+/*****************************************************
+ * Expand macro in place in buf.
+ * Only look at the text in buf from start to end.
+ */
+
+void Macro::expand(OutBuffer *buf, size_t start, size_t *pend,
+        const utf8_t *arg, size_t arglen)
+{
+#if 0
+    printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, *pend, arglen, arg);
+    printf("Buf is: '%.*s'\n", *pend - start, buf->data + start);
+#endif
+
+    // limit recursive expansion
+    static int nest;
+    static const int nestLimit = 1000;
+    if (nest > nestLimit)
+    {
+        error(Loc(), "DDoc macro expansion limit exceeded; more than %d "
+            "expansions.", nestLimit);
+        return;
+    }
+    nest++;
+
+    size_t end = *pend;
+    assert(start <= end);
+    assert(end <= buf->offset);
+
+    /* First pass - replace $0
+     */
+    arg = memdup(arg, arglen);
+    for (size_t u = start; u + 1 < end; )
+    {
+        utf8_t *p = (utf8_t *)buf->data;   // buf->data is not loop invariant
+
+        /* Look for $0, but not $$0, and replace it with arg.
+         */
+        if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+'))
+        {
+            if (u > start && p[u - 1] == '$')
+            {   // Don't expand $$0, but replace it with $0
+                buf->remove(u - 1, 1);
+                end--;
+                u += 1; // now u is one past the closing '1'
+                continue;
+            }
+
+            utf8_t c = p[u + 1];
+            int n = (c == '+') ? -1 : c - '0';
+
+            const utf8_t *marg;
+            size_t marglen;
+            if (n == 0)
+            {
+                marg = arg;
+                marglen = arglen;
+            }
+            else
+                extractArgN(arg, arglen, &marg, &marglen, n);
+            if (marglen == 0)
+            {   // Just remove macro invocation
+                //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
+                buf->remove(u, 2);
+                end -= 2;
+            }
+            else if (c == '+')
+            {
+                // Replace '$+' with 'arg'
+                //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
+                buf->remove(u, 2);
+                buf->insert(u, marg, marglen);
+                end += marglen - 2;
+
+                // Scan replaced text for further expansion
+                size_t mend = u + marglen;
+                expand(buf, u, &mend, NULL, 0);
+                end += mend - (u + marglen);
+                u = mend;
+            }
+            else
+            {
+                // Replace '$1' with '\xFF{arg\xFF}'
+                //printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], marglen, marg);
+                buf->data[u] = 0xFF;
+                buf->data[u + 1] = '{';
+                buf->insert(u + 2, marg, marglen);
+                buf->insert(u + 2 + marglen, (const char *)"\xFF}", 2);
+                end += -2 + 2 + marglen + 2;
+
+                // Scan replaced text for further expansion
+                size_t mend = u + 2 + marglen;
+                expand(buf, u + 2, &mend, NULL, 0);
+                end += mend - (u + 2 + marglen);
+                u = mend;
+            }
+            //printf("u = %d, end = %d\n", u, end);
+            //printf("#%.*s#\n", end, &buf->data[0]);
+            continue;
+        }
+
+        u++;
+    }
+
+    /* Second pass - replace other macros
+     */
+    for (size_t u = start; u + 4 < end; )
+    {
+        utf8_t *p = (utf8_t *)buf->data;   // buf->data is not loop invariant
+
+        /* A valid start of macro expansion is $(c, where c is
+         * an id start character, and not $$(c.
+         */
+        if (p[u] == '$' && p[u + 1] == '(' && isIdStart(p+u+2))
+        {
+            //printf("\tfound macro start '%c'\n", p[u + 2]);
+            utf8_t *name = p + u + 2;
+            size_t namelen = 0;
+
+            const utf8_t *marg;
+            size_t marglen;
+
+            size_t v;
+            /* Scan forward to find end of macro name and
+             * beginning of macro argument (marg).
+             */
+            for (v = u + 2; v < end; v+=utfStride(p+v))
+            {
+
+                if (!isIdTail(p+v))
+                {   // We've gone past the end of the macro name.
+                    namelen = v - (u + 2);
+                    break;
+                }
+            }
+
+            v += extractArgN(p + v, end - v, &marg, &marglen, 0);
+            assert(v <= end);
+
+            if (v < end)
+            {   // v is on the closing ')'
+                if (u > start && p[u - 1] == '$')
+                {   // Don't expand $$(NAME), but replace it with $(NAME)
+                    buf->remove(u - 1, 1);
+                    end--;
+                    u = v;      // now u is one past the closing ')'
+                    continue;
+                }
+
+                Macro *m = search(name, namelen);
+
+                if (!m)
+                {
+                    static const char undef[] = "DDOC_UNDEFINED_MACRO";
+                    m = search((const utf8_t *)undef, strlen(undef));
+                    if (m)
+                    {
+                        // Macro was not defined, so this is an expansion of
+                        //   DDOC_UNDEFINED_MACRO. Prepend macro name to args.
+                        // marg = name[ ] ~ "," ~ marg[ ];
+                        if (marglen)
+                        {
+                            utf8_t *q = (utf8_t *)mem.xmalloc(namelen + 1 + marglen);
+                            assert(q);
+                            memcpy(q, name, namelen);
+                            q[namelen] = ',';
+                            memcpy(q + namelen + 1, marg, marglen);
+                            marg = q;
+                            marglen += namelen + 1;
+                        }
+                        else
+                        {
+                            marg = name;
+                            marglen = namelen;
+                        }
+                    }
+                }
+
+                if (m)
+                {
+                    if (m->inuse && marglen == 0)
+                    {   // Remove macro invocation
+                        buf->remove(u, v + 1 - u);
+                        end -= v + 1 - u;
+                    }
+                    else if (m->inuse &&
+                             ((arglen == marglen && memcmp(arg, marg, arglen) == 0) ||
+                              (arglen + 4 == marglen &&
+                               marg[0] == 0xFF &&
+                               marg[1] == '{' &&
+                               memcmp(arg, marg + 2, arglen) == 0 &&
+                               marg[marglen - 2] == 0xFF &&
+                               marg[marglen - 1] == '}'
+                              )
+                             )
+                            )
+                    {
+                        /* Recursive expansion:
+                         *   marg is same as arg (with blue paint added)
+                         * Just leave in place.
+                         */
+                    }
+                    else
+                    {
+                        //printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", m->namelen, m->name, marglen, marg, m->textlen, m->text);
+                        marg = memdup(marg, marglen);
+                        // Insert replacement text
+                        buf->spread(v + 1, 2 + m->textlen + 2);
+                        buf->data[v + 1] = 0xFF;
+                        buf->data[v + 2] = '{';
+                        memcpy(buf->data + v + 3, m->text, m->textlen);
+                        buf->data[v + 3 + m->textlen] = 0xFF;
+                        buf->data[v + 3 + m->textlen + 1] = '}';
+
+                        end += 2 + m->textlen + 2;
+
+                        // Scan replaced text for further expansion
+                        m->inuse++;
+                        size_t mend = v + 1 + 2+m->textlen+2;
+                        expand(buf, v + 1, &mend, marg, marglen);
+                        end += mend - (v + 1 + 2+m->textlen+2);
+                        m->inuse--;
+
+                        buf->remove(u, v + 1 - u);
+                        end -= v + 1 - u;
+                        u += mend - (v + 1);
+                        mem.xfree((utf8_t *)marg);
+                        //printf("u = %d, end = %d\n", u, end);
+                        //printf("#%.*s#\n", end - u, &buf->data[u]);
+                        continue;
+                    }
+                }
+                else
+                {
+                    // Replace $(NAME) with nothing
+                    buf->remove(u, v + 1 - u);
+                    end -= (v + 1 - u);
+                    continue;
+                }
+            }
+        }
+        u++;
+    }
+    mem.xfree((utf8_t *)arg);
+    *pend = end;
+    nest--;
+}
diff --git a/gcc/d/dfrontend/dmangle.c b/gcc/d/dfrontend/dmangle.c
new file mode 100644
index 00000000000..23ac6aeeb56
--- /dev/null
+++ b/gcc/d/dfrontend/dmangle.c
@@ -0,0 +1,897 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/mangle.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "root.h"
+
+#include "init.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "mtype.h"
+#include "attrib.h"
+#include "target.h"
+#include "template.h"
+#include "id.h"
+#include "module.h"
+#include "enum.h"
+#include "expression.h"
+#include "utf.h"
+
+void mangleToBuffer(Type *t, OutBuffer *buf);
+typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param);
+int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL);
+
+static const char *mangleChar[TMAX];
+
+void initTypeMangle()
+{
+    mangleChar[Tarray] = "A";
+    mangleChar[Tsarray] = "G";
+    mangleChar[Taarray] = "H";
+    mangleChar[Tpointer] = "P";
+    mangleChar[Treference] = "R";
+    mangleChar[Tfunction] = "F";
+    mangleChar[Tident] = "I";
+    mangleChar[Tclass] = "C";
+    mangleChar[Tstruct] = "S";
+    mangleChar[Tenum] = "E";
+    mangleChar[Tdelegate] = "D";
+
+    mangleChar[Tnone] = "n";
+    mangleChar[Tvoid] = "v";
+    mangleChar[Tint8] = "g";
+    mangleChar[Tuns8] = "h";
+    mangleChar[Tint16] = "s";
+    mangleChar[Tuns16] = "t";
+    mangleChar[Tint32] = "i";
+    mangleChar[Tuns32] = "k";
+    mangleChar[Tint64] = "l";
+    mangleChar[Tuns64] = "m";
+    mangleChar[Tint128] = "zi";
+    mangleChar[Tuns128] = "zk";
+    mangleChar[Tfloat32] = "f";
+    mangleChar[Tfloat64] = "d";
+    mangleChar[Tfloat80] = "e";
+
+    mangleChar[Timaginary32] = "o";
+    mangleChar[Timaginary64] = "p";
+    mangleChar[Timaginary80] = "j";
+    mangleChar[Tcomplex32] = "q";
+    mangleChar[Tcomplex64] = "r";
+    mangleChar[Tcomplex80] = "c";
+
+    mangleChar[Tbool] = "b";
+    mangleChar[Tchar] = "a";
+    mangleChar[Twchar] = "u";
+    mangleChar[Tdchar] = "w";
+
+    // '@' shouldn't appear anywhere in the deco'd names
+    mangleChar[Tinstance] = "@";
+    mangleChar[Terror] = "@";
+    mangleChar[Ttypeof] = "@";
+    mangleChar[Ttuple] = "B";
+    mangleChar[Tslice] = "@";
+    mangleChar[Treturn] = "@";
+    mangleChar[Tvector] = "@";
+
+    mangleChar[Tnull] = "n";    // same as TypeNone
+
+    for (size_t i = 0; i < TMAX; i++)
+    {
+        if (!mangleChar[i])
+            fprintf(stderr, "ty = %llu\n", (ulonglong)i);
+        assert(mangleChar[i]);
+    }
+}
+
+/*********************************
+ * Mangling for mod.
+ */
+void MODtoDecoBuffer(OutBuffer *buf, MOD mod)
+{
+    switch (mod)
+    {
+        case 0:
+            break;
+        case MODconst:
+            buf->writeByte('x');
+            break;
+        case MODimmutable:
+            buf->writeByte('y');
+            break;
+        case MODshared:
+            buf->writeByte('O');
+            break;
+        case MODshared | MODconst:
+            buf->writestring("Ox");
+            break;
+        case MODwild:
+            buf->writestring("Ng");
+            break;
+        case MODwildconst:
+            buf->writestring("Ngx");
+            break;
+        case MODshared | MODwild:
+            buf->writestring("ONg");
+            break;
+        case MODshared | MODwildconst:
+            buf->writestring("ONgx");
+            break;
+        default:
+            assert(0);
+    }
+}
+
+class Mangler : public Visitor
+{
+public:
+    OutBuffer *buf;
+
+    Mangler(OutBuffer *buf)
+    {
+        this->buf = buf;
+    }
+
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    /**************************************************
+     * Type mangling
+     */
+
+    void visitWithMask(Type *t, unsigned char modMask)
+    {
+        if (modMask != t->mod)
+        {
+            MODtoDecoBuffer(buf, t->mod);
+        }
+        t->accept(this);
+    }
+
+    void visit(Type *t)
+    {
+        buf->writestring(mangleChar[t->ty]);
+    }
+
+    void visit(TypeNext *t)
+    {
+        visit((Type *)t);
+        visitWithMask(t->next, t->mod);
+    }
+
+    void visit(TypeVector *t)
+    {
+        buf->writestring("Nh");
+        visitWithMask(t->basetype, t->mod);
+    }
+
+    void visit(TypeSArray *t)
+    {
+        visit((Type *)t);
+        if (t->dim)
+            buf->printf("%llu", t->dim->toInteger());
+        if (t->next)
+            visitWithMask(t->next, t->mod);
+    }
+
+    void visit(TypeDArray *t)
+    {
+        visit((Type *)t);
+        if (t->next)
+            visitWithMask(t->next, t->mod);
+    }
+
+    void visit(TypeAArray *t)
+    {
+        visit((Type *)t);
+        visitWithMask(t->index, 0);
+        visitWithMask(t->next, t->mod);
+    }
+
+    void visit(TypeFunction *t)
+    {
+        //printf("TypeFunction::toDecoBuffer() t = %p %s\n", t, t->toChars());
+        //static int nest; if (++nest == 50) *(char*)0=0;
+
+        mangleFuncType(t, t, t->mod, t->next);
+    }
+
+    void mangleFuncType(TypeFunction *t, TypeFunction *ta, unsigned char modMask, Type *tret)
+    {
+        //printf("mangleFuncType() %s\n", t->toChars());
+        if (t->inuse)
+        {
+            t->inuse = 2;       // flag error to caller
+            return;
+        }
+        t->inuse++;
+
+        if (modMask != t->mod)
+            MODtoDecoBuffer(buf, t->mod);
+
+        unsigned char mc;
+        switch (t->linkage)
+        {
+            case LINKd:             mc = 'F';       break;
+            case LINKc:             mc = 'U';       break;
+            case LINKwindows:       mc = 'W';       break;
+            case LINKpascal:        mc = 'V';       break;
+            case LINKcpp:           mc = 'R';       break;
+            case LINKobjc:          mc = 'Y';       break;
+            default:
+                assert(0);
+        }
+        buf->writeByte(mc);
+
+        if (ta->purity || ta->isnothrow || ta->isnogc || ta->isproperty || ta->isref || ta->trust || ta->isreturn || ta->isscope)
+        {
+            if (ta->purity)
+                buf->writestring("Na");
+            if (ta->isnothrow)
+                buf->writestring("Nb");
+            if (ta->isref)
+                buf->writestring("Nc");
+            if (ta->isproperty)
+                buf->writestring("Nd");
+            if (ta->isnogc)
+                buf->writestring("Ni");
+            if (ta->isreturn)
+                buf->writestring("Nj");
+            if (ta->isscope && !ta->isreturn && !ta->isscopeinferred)
+                buf->writestring("Nl");
+            switch (ta->trust)
+            {
+                case TRUSTtrusted:
+                    buf->writestring("Ne");
+                    break;
+                case TRUSTsafe:
+                    buf->writestring("Nf");
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        // Write argument types
+        paramsToDecoBuffer(t->parameters);
+        //if (buf->data[buf->offset - 1] == '@') halt();
+        buf->writeByte('Z' - t->varargs);   // mark end of arg list
+        if (tret != NULL)
+            visitWithMask(tret, 0);
+
+        t->inuse--;
+    }
+
+    void visit(TypeIdentifier *t)
+    {
+        visit((Type *)t);
+        const char *name = t->ident->toChars();
+        size_t len = strlen(name);
+        buf->printf("%u%s", (unsigned)len, name);
+    }
+
+    void visit(TypeEnum *t)
+    {
+        visit((Type *)t);
+        t->sym->accept(this);
+    }
+
+    void visit(TypeStruct *t)
+    {
+        //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", t->toChars(), name);
+        visit((Type *)t);
+        t->sym->accept(this);
+    }
+
+    void visit(TypeClass *t)
+    {
+        //printf("TypeClass::toDecoBuffer('%s' mod=%x) = '%s'\n", t->toChars(), mod, name);
+        visit((Type *)t);
+        t->sym->accept(this);
+    }
+
+    void visit(TypeTuple *t)
+    {
+        //printf("TypeTuple::toDecoBuffer() t = %p, %s\n", t, t->toChars());
+        visit((Type *)t);
+
+        OutBuffer buf2;
+        buf2.reserve(32);
+        Mangler v(&buf2);
+        v.paramsToDecoBuffer(t->arguments);
+        int len = (int)buf2.offset;
+        buf->printf("%d%.*s", len, len, buf2.extractData());
+    }
+
+    void visit(TypeNull *t)
+    {
+        visit((Type *)t);
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    void mangleDecl(Declaration *sthis)
+    {
+        mangleParent(sthis);
+
+        assert(sthis->ident);
+        const char *id = sthis->ident->toChars();
+        toBuffer(id, sthis);
+
+        if (FuncDeclaration *fd = sthis->isFuncDeclaration())
+        {
+            mangleFunc(fd, false);
+        }
+        else if (sthis->type->deco)
+        {
+            buf->writestring(sthis->type->deco);
+        }
+        else
+            assert(0);
+    }
+
+    void mangleParent(Dsymbol *s)
+    {
+        Dsymbol *p;
+        if (TemplateInstance *ti = s->isTemplateInstance())
+            p = ti->isTemplateMixin() ? ti->parent : ti->tempdecl->parent;
+        else
+            p = s->parent;
+
+        if (p)
+        {
+            mangleParent(p);
+
+            if (p->getIdent())
+            {
+                const char *id = p->ident->toChars();
+                toBuffer(id, s);
+
+                if (FuncDeclaration *f = p->isFuncDeclaration())
+                    mangleFunc(f, true);
+            }
+            else
+                buf->writeByte('0');
+        }
+    }
+
+    void mangleFunc(FuncDeclaration *fd, bool inParent)
+    {
+        //printf("deco = '%s'\n", fd->type->deco ? fd->type->deco : "null");
+        //printf("fd->type = %s\n", fd->type->toChars());
+        if (fd->needThis() || fd->isNested())
+            buf->writeByte('M');
+        if (inParent)
+        {
+            TypeFunction *tf = (TypeFunction *)fd->type;
+            TypeFunction *tfo = (TypeFunction *)fd->originalType;
+            mangleFuncType(tf, tfo, 0, NULL);
+        }
+        else if (fd->type->deco)
+        {
+            buf->writestring(fd->type->deco);
+        }
+        else
+        {
+            printf("[%s] %s %s\n", fd->loc.toChars(), fd->toChars(), fd->type->toChars());
+            assert(0);  // don't mangle function until semantic3 done.
+        }
+    }
+
+    /************************************************************
+     * Write length prefixed string to buf.
+     */
+    void toBuffer(const char *id, Dsymbol *s)
+    {
+        size_t len = strlen(id);
+        if (len >= 8 * 1024 * 1024)         // 8 megs ought be enough for anyone
+            s->error("excessive length %llu for symbol, possible recursive expansion?", len);
+        else
+        {
+            buf->printf("%llu", (ulonglong)len);
+            buf->write(id, len);
+        }
+    }
+
+    void visit(Declaration *d)
+    {
+        //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
+        //        d, d->toChars(), d->parent ? d->parent->toChars() : "null", d->linkage);
+        if (!d->parent || d->parent->isModule() || d->linkage == LINKcpp) // if at global scope
+        {
+            switch (d->linkage)
+            {
+                case LINKd:
+                    break;
+
+                case LINKc:
+                case LINKwindows:
+                case LINKpascal:
+                case LINKobjc:
+                    buf->writestring(d->ident->toChars());
+                    return;
+
+                case LINKcpp:
+                    buf->writestring(Target::toCppMangle(d));
+                    return;
+
+                case LINKdefault:
+                    d->error("forward declaration");
+                    buf->writestring(d->ident->toChars());
+                    return;
+
+                default:
+                    fprintf(stderr, "'%s', linkage = %d\n", d->toChars(), d->linkage);
+                    assert(0);
+                    return;
+            }
+        }
+
+        buf->writestring("_D");
+        mangleDecl(d);
+
+    #ifdef DEBUG
+        assert(buf->data);
+        size_t len = buf->offset;
+        assert(len > 0);
+        for (size_t i = 0; i < len; i++)
+        {
+            assert(buf->data[i] == '_' ||
+                   buf->data[i] == '@' ||
+                   buf->data[i] == '?' ||
+                   buf->data[i] == '$' ||
+                   isalnum(buf->data[i]) || buf->data[i] & 0x80);
+        }
+    #endif
+    }
+
+    /******************************************************************************
+     * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
+     * If and only if there is no overloads, mangle() could return
+     * exact mangled name.
+     *
+     *      module test;
+     *      void foo(long) {}           // _D4test3fooFlZv
+     *      void foo(string) {}         // _D4test3fooFAyaZv
+     *
+     *      // from FuncDeclaration::mangle().
+     *      pragma(msg, foo.mangleof);  // prints unexact mangled name "4test3foo"
+     *                                  // by calling Dsymbol::mangle()
+     *
+     *      // from FuncAliasDeclaration::mangle()
+     *      pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof);  // "_D4test3fooFlZv"
+     *      pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof);  // "_D4test3fooFAyaZv"
+     *
+     * If a function has no overloads, .mangleof property still returns exact mangled name.
+     *
+     *      void bar() {}
+     *      pragma(msg, bar.mangleof);  // still prints "_D4test3barFZv"
+     *                                  // by calling FuncDeclaration::mangleExact().
+     */
+    void visit(FuncDeclaration *fd)
+    {
+        if (fd->isUnique())
+            mangleExact(fd);
+        else
+            visit((Dsymbol *)fd);
+    }
+
+    // ditto
+    void visit(FuncAliasDeclaration *fd)
+    {
+        FuncDeclaration *f = fd->toAliasFunc();
+        FuncAliasDeclaration *fa = f->isFuncAliasDeclaration();
+        if (!fd->hasOverloads && !fa)
+        {
+            mangleExact(f);
+            return;
+        }
+        if (fa)
+        {
+            fa->accept(this);
+            return;
+        }
+        visit((Dsymbol *)fd);
+    }
+
+    void visit(OverDeclaration *od)
+    {
+        if (od->overnext)
+        {
+            visit((Dsymbol *)od);
+            return;
+        }
+
+        if (FuncDeclaration *fd = od->aliassym->isFuncDeclaration())
+        {
+            if (!od->hasOverloads || fd->isUnique())
+            {
+                mangleExact(fd);
+                return;
+            }
+        }
+        if (TemplateDeclaration *td = od->aliassym->isTemplateDeclaration())
+        {
+            if (!od->hasOverloads || td->overnext == NULL)
+            {
+                td->accept(this);
+                return;
+            }
+        }
+        visit((Dsymbol *)od);
+    }
+
+    void mangleExact(FuncDeclaration *fd)
+    {
+        assert(!fd->isFuncAliasDeclaration());
+
+        if (fd->mangleOverride)
+        {
+            buf->writestring(fd->mangleOverride);
+            return;
+        }
+
+        if (fd->isMain())
+        {
+            buf->writestring("_Dmain");
+            return;
+        }
+
+        if (fd->isWinMain() || fd->isDllMain() || fd->ident == Id::tls_get_addr)
+        {
+            buf->writestring(fd->ident->toChars());
+            return;
+        }
+
+        visit((Declaration *)fd);
+    }
+
+    void visit(VarDeclaration *vd)
+    {
+        if (vd->mangleOverride)
+        {
+            buf->writestring(vd->mangleOverride);
+            return;
+        }
+
+        visit((Declaration *)vd);
+    }
+
+    void visit(AggregateDeclaration *ad)
+    {
+        ClassDeclaration *cd = ad->isClassDeclaration();
+        Dsymbol *parentsave = ad->parent;
+        if (cd)
+        {
+            /* These are reserved to the compiler, so keep simple
+             * names for them.
+             */
+            if (cd->ident == Id::Exception && cd->parent->ident == Id::object ||
+                cd->ident == Id::TypeInfo ||
+                cd->ident == Id::TypeInfo_Struct ||
+                cd->ident == Id::TypeInfo_Class ||
+                cd->ident == Id::TypeInfo_Tuple ||
+                cd == ClassDeclaration::object ||
+                cd == Type::typeinfoclass ||
+                cd == Module::moduleinfo ||
+                strncmp(cd->ident->toChars(), "TypeInfo_", 9) == 0)
+            {
+                // Don't mangle parent
+                ad->parent = NULL;
+            }
+        }
+
+        visit((Dsymbol *)ad);
+
+        ad->parent = parentsave;
+    }
+
+    void visit(TemplateInstance *ti)
+    {
+    #if 0
+        printf("TemplateInstance::mangle() %p %s", ti, ti->toChars());
+        if (ti->parent)
+            printf("  parent = %s %s", ti->parent->kind(), ti->parent->toChars());
+        printf("\n");
+    #endif
+
+        if (!ti->tempdecl)
+            ti->error("is not defined");
+        else
+            mangleParent(ti);
+
+        ti->getIdent();
+        const char *id = ti->ident ? ti->ident->toChars() : ti->toChars();
+        toBuffer(id, ti);
+
+        //printf("TemplateInstance::mangle() %s = %s\n", ti->toChars(), ti->id);
+    }
+
+    void visit(Dsymbol *s)
+    {
+    #if 0
+        printf("Dsymbol::mangle() '%s'", s->toChars());
+        if (s->parent)
+            printf("  parent = %s %s", s->parent->kind(), s->parent->toChars());
+        printf("\n");
+    #endif
+
+        mangleParent(s);
+
+        const char *id = s->ident ? s->ident->toChars() : s->toChars();
+        toBuffer(id, s);
+
+        //printf("Dsymbol::mangle() %s = %s\n", s->toChars(), id);
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    void visit(Expression *e)
+    {
+        e->error("expression %s is not a valid template value argument", e->toChars());
+    }
+
+    void visit(IntegerExp *e)
+    {
+        if ((sinteger_t)e->value < 0)
+            buf->printf("N%lld", -e->value);
+        else
+            buf->printf("i%lld",  e->value);
+    }
+
+    void visit(RealExp *e)
+    {
+        buf->writeByte('e');
+        realToMangleBuffer(e->value);
+    }
+
+    void realToMangleBuffer(real_t value)
+    {
+        /* Rely on %A to get portable mangling.
+         * Must munge result to get only identifier characters.
+         *
+         * Possible values from %A  => mangled result
+         * NAN                      => NAN
+         * -INF                     => NINF
+         * INF                      => INF
+         * -0X1.1BC18BA997B95P+79   => N11BC18BA997B95P79
+         * 0X1.9P+2                 => 19P2
+         */
+
+        if (CTFloat::isNaN(value))
+            buf->writestring("NAN");        // no -NAN bugs
+        else if (CTFloat::isInfinity(value))
+            buf->writestring(value < CTFloat::zero ? "NINF" : "INF");
+        else
+        {
+            const size_t BUFFER_LEN = 36;
+            char buffer[BUFFER_LEN];
+            size_t n = CTFloat::sprint(buffer, 'A', value);
+            assert(n < BUFFER_LEN);
+            for (size_t i = 0; i < n; i++)
+            {
+                char c = buffer[i];
+                switch (c)
+                {
+                    case '-':
+                        buf->writeByte('N');
+                        break;
+
+                    case '+':
+                    case 'X':
+                    case '.':
+                        break;
+
+                    case '0':
+                        if (i < 2)
+                            break;          // skip leading 0X
+                    default:
+                        buf->writeByte(c);
+                        break;
+                }
+            }
+        }
+    }
+
+    void visit(ComplexExp *e)
+    {
+        buf->writeByte('c');
+        realToMangleBuffer(e->toReal());
+        buf->writeByte('c');        // separate the two
+        realToMangleBuffer(e->toImaginary());
+    }
+
+    void visit(NullExp *e)
+    {
+        buf->writeByte('n');
+    }
+
+    void visit(StringExp *e)
+    {
+        char m;
+        OutBuffer tmp;
+        utf8_t *q;
+        size_t qlen;
+
+        /* Write string in UTF-8 format
+         */
+        switch (e->sz)
+        {
+            case 1:
+                m = 'a';
+                q = (utf8_t *)e->string;
+                qlen = e->len;
+                break;
+
+            case 2:
+                m = 'w';
+                for (size_t u = 0; u < e->len; )
+                {
+                    unsigned c;
+                    const char *p = utf_decodeWchar((unsigned short *)e->string, e->len, &u, &c);
+                    if (p)
+                        e->error("%s", p);
+                    else
+                        tmp.writeUTF8(c);
+                }
+                q = (utf8_t *)tmp.data;
+                qlen = tmp.offset;
+                break;
+
+            case 4:
+                m = 'd';
+                for (size_t u = 0; u < e->len; u++)
+                {
+                    unsigned c = ((unsigned *)e->string)[u];
+                    if (!utf_isValidDchar(c))
+                        e->error("invalid UCS-32 char \\U%08x", c);
+                    else
+                        tmp.writeUTF8(c);
+                }
+                q = (utf8_t *)tmp.data;
+                qlen = tmp.offset;
+                break;
+
+            default:
+                assert(0);
+        }
+        buf->reserve(1 + 11 + 2 * qlen);
+        buf->writeByte(m);
+        buf->printf("%d_", (int)qlen); // nbytes <= 11
+
+        for (utf8_t *p = (utf8_t *)buf->data + buf->offset, *pend = p + 2 * qlen;
+             p < pend; p += 2, ++q)
+        {
+            utf8_t hi = *q >> 4 & 0xF;
+            p[0] = (utf8_t)(hi < 10 ? hi + '0' : hi - 10 + 'a');
+            utf8_t lo = *q & 0xF;
+            p[1] = (utf8_t)(lo < 10 ? lo + '0' : lo - 10 + 'a');
+        }
+        buf->offset += 2 * qlen;
+    }
+
+    void visit(ArrayLiteralExp *e)
+    {
+        size_t dim = e->elements ? e->elements->dim : 0;
+        buf->printf("A%u", dim);
+        for (size_t i = 0; i < dim; i++)
+        {
+            e->getElement(i)->accept(this);
+        }
+    }
+
+    void visit(AssocArrayLiteralExp *e)
+    {
+        size_t dim = e->keys->dim;
+        buf->printf("A%u", dim);
+        for (size_t i = 0; i < dim; i++)
+        {
+            (*e->keys)[i]->accept(this);
+            (*e->values)[i]->accept(this);
+        }
+    }
+
+    void visit(StructLiteralExp *e)
+    {
+        size_t dim = e->elements ? e->elements->dim : 0;
+        buf->printf("S%u", dim);
+        for (size_t i = 0; i < dim; i++)
+        {
+            Expression *ex = (*e->elements)[i];
+            if (ex)
+                ex->accept(this);
+            else
+                buf->writeByte('v');        // 'v' for void
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    void paramsToDecoBuffer(Parameters *parameters)
+    {
+        //printf("Parameter::paramsToDecoBuffer()\n");
+        Parameter_foreach(parameters, &paramsToDecoBufferDg, (void *)this);
+    }
+
+    static int paramsToDecoBufferDg(void *ctx, size_t n, Parameter *p)
+    {
+        p->accept((Visitor *)ctx);
+        return 0;
+    }
+
+    void visit(Parameter *p)
+    {
+        if (p->storageClass & STCscope && !(p->storageClass & STCscopeinferred))
+            buf->writeByte('M');
+        // 'return inout ref' is the same as 'inout ref'
+        if ((p->storageClass & (STCreturn | STCwild)) == STCreturn)
+            buf->writestring("Nk");
+        switch (p->storageClass & (STCin | STCout | STCref | STClazy))
+        {
+            case 0:
+            case STCin:
+                break;
+            case STCout:
+                buf->writeByte('J');
+                break;
+            case STCref:
+                buf->writeByte('K');
+                break;
+            case STClazy:
+                buf->writeByte('L');
+                break;
+            default:
+    #ifdef DEBUG
+                printf("storageClass = x%llx\n", p->storageClass & (STCin | STCout | STCref | STClazy));
+                halt();
+    #endif
+                assert(0);
+        }
+        visitWithMask(p->type, 0);
+    }
+};
+
+/******************************************************************************
+ * Returns exact mangled name of function.
+ */
+const char *mangleExact(FuncDeclaration *fd)
+{
+    if (!fd->mangleString)
+    {
+        OutBuffer buf;
+        Mangler v(&buf);
+        v.mangleExact(fd);
+        fd->mangleString = buf.extractString();
+    }
+    return fd->mangleString;
+}
+
+void mangleToBuffer(Type *t, OutBuffer *buf)
+{
+    Mangler v(buf);
+    v.visitWithMask(t, 0);
+}
+
+void mangleToBuffer(Expression *e, OutBuffer *buf)
+{
+    Mangler v(buf);
+    e->accept(&v);
+}
+
+void mangleToBuffer(Dsymbol *s, OutBuffer *buf)
+{
+    Mangler v(buf);
+    s->accept(&v);
+}
diff --git a/gcc/d/dfrontend/dmodule.c b/gcc/d/dfrontend/dmodule.c
new file mode 100644
index 00000000000..f276767e434
--- /dev/null
+++ b/gcc/d/dfrontend/dmodule.c
@@ -0,0 +1,1427 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/module.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "module.h"
+#include "parse.h"
+#include "scope.h"
+#include "identifier.h"
+#include "id.h"
+#include "import.h"
+#include "dsymbol.h"
+#include "expression.h"
+#include "lexer.h"
+#include "attrib.h"
+#include "target.h"
+
+// For getcwd()
+#if _WIN32
+#include <direct.h>
+#endif
+#if POSIX
+#include <unistd.h>
+#endif
+
+AggregateDeclaration *Module::moduleinfo;
+
+Module *Module::rootModule;
+DsymbolTable *Module::modules;
+Modules Module::amodules;
+
+Dsymbols Module::deferred;  // deferred Dsymbol's needing semantic() run on them
+Dsymbols Module::deferred2; // deferred Dsymbol's needing semantic2() run on them
+Dsymbols Module::deferred3; // deferred Dsymbol's needing semantic3() run on them
+unsigned Module::dprogress;
+
+const char *lookForSourceFile(const char **path, const char *filename);
+
+void Module::_init()
+{
+    modules = new DsymbolTable();
+}
+
+Module::Module(const char *filename, Identifier *ident, int doDocComment, int doHdrGen)
+        : Package(ident)
+{
+    const char *srcfilename;
+
+//    printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars());
+    this->arg = filename;
+    md = NULL;
+    errors = 0;
+    numlines = 0;
+    members = NULL;
+    isDocFile = 0;
+    isPackageFile = false;
+    needmoduleinfo = 0;
+    selfimports = 0;
+    rootimports = 0;
+    insearch = 0;
+    searchCacheIdent = NULL;
+    searchCacheSymbol = NULL;
+    searchCacheFlags = 0;
+    decldefs = NULL;
+    sictor = NULL;
+    sctor = NULL;
+    sdtor = NULL;
+    ssharedctor = NULL;
+    sshareddtor = NULL;
+    stest = NULL;
+    sfilename = NULL;
+    importedFrom = NULL;
+    srcfile = NULL;
+    srcfilePath = NULL;
+    docfile = NULL;
+
+    debuglevel = 0;
+    debugids = NULL;
+    debugidsNot = NULL;
+    versionlevel = 0;
+    versionids = NULL;
+    versionidsNot = NULL;
+
+    macrotable = NULL;
+    escapetable = NULL;
+    doppelganger = 0;
+    cov = NULL;
+    covb = NULL;
+
+    nameoffset = 0;
+    namelen = 0;
+
+    srcfilename = FileName::defaultExt(filename, global.mars_ext);
+
+    if (global.run_noext && global.params.run &&
+        !FileName::ext(filename) &&
+        FileName::exists(srcfilename) == 0 &&
+        FileName::exists(filename) == 1)
+    {
+        FileName::free(srcfilename);
+        srcfilename = FileName::removeExt(filename);    // just does a mem.strdup(filename)
+    }
+    else if (!FileName::equalsExt(srcfilename, global.mars_ext) &&
+        !FileName::equalsExt(srcfilename, global.hdr_ext) &&
+        !FileName::equalsExt(srcfilename, "dd"))
+    {
+        error("source file name '%s' must have .%s extension", srcfilename, global.mars_ext);
+        fatal();
+    }
+    srcfile = new File(srcfilename);
+    if (!FileName::absolute(srcfilename))
+        srcfilePath = getcwd(NULL, 0);
+
+    objfile = setOutfile(global.params.objname, global.params.objdir, filename, global.obj_ext);
+
+    if (doDocComment)
+        setDocfile();
+
+    if (doHdrGen)
+        hdrfile = setOutfile(global.params.hdrname, global.params.hdrdir, arg, global.hdr_ext);
+
+    //objfile = new File(objfilename);
+}
+
+Module *Module::create(const char *filename, Identifier *ident, int doDocComment, int doHdrGen)
+{
+    return new Module(filename, ident, doDocComment, doHdrGen);
+}
+
+void Module::setDocfile()
+{
+    docfile = setOutfile(global.params.docname, global.params.docdir, arg, global.doc_ext);
+}
+
+/*********************************************
+ * Combines things into output file name for .html and .di files.
+ * Input:
+ *      name    Command line name given for the file, NULL if none
+ *      dir     Command line directory given for the file, NULL if none
+ *      arg     Name of the source file
+ *      ext     File name extension to use if 'name' is NULL
+ *      global.params.preservePaths     get output path from arg
+ *      srcfile Input file - output file name must not match input file
+ */
+
+File *Module::setOutfile(const char *name, const char *dir, const char *arg, const char *ext)
+{
+    const char *docfilename;
+
+    if (name)
+    {
+        docfilename = name;
+    }
+    else
+    {
+        const char *argdoc;
+        if (global.params.preservePaths)
+            argdoc = arg;
+        else
+            argdoc = FileName::name(arg);
+
+        // If argdoc doesn't have an absolute path, make it relative to dir
+        if (!FileName::absolute(argdoc))
+        {   //FileName::ensurePathExists(dir);
+            argdoc = FileName::combine(dir, argdoc);
+        }
+        docfilename = FileName::forceExt(argdoc, ext);
+    }
+
+    if (FileName::equals(docfilename, srcfile->name->str))
+    {
+        error("source file and output file have same name '%s'", srcfile->name->str);
+        fatal();
+    }
+
+    return new File(docfilename);
+}
+
+void Module::deleteObjFile()
+{
+    if (global.params.obj)
+        objfile->remove();
+    if (docfile)
+        docfile->remove();
+}
+
+const char *Module::kind()
+{
+    return "module";
+}
+
+static void checkModFileAlias(OutBuffer *buf, OutBuffer *dotmods,
+                              Array<const char *> *ms, size_t msdim, const char *p)
+{
+    /* Check and replace the contents of buf[] with
+     * an alias string from global.params.modFileAliasStrings[]
+     */
+    dotmods->writestring(p);
+    for (size_t j = msdim; j--;)
+    {
+        const char *m = (*ms)[j];
+        const char *q = strchr(m, '=');
+        assert(q);
+        if (dotmods->offset <= q - m && memcmp(dotmods->peekString(), m, q - m) == 0)
+        {
+            buf->reset();
+            size_t qlen = strlen(q + 1);
+            if (qlen && (q[qlen] == '/' || q[qlen] == '\\'))
+                --qlen;             // remove trailing separator
+            buf->write(q + 1, qlen);
+            break;                  // last matching entry in ms[] wins
+        }
+    }
+    dotmods->writeByte('.');
+}
+
+Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident)
+{
+    //printf("Module::load(ident = '%s')\n", ident->toChars());
+
+    // Build module filename by turning:
+    //  foo.bar.baz
+    // into:
+    //  foo\bar\baz
+    const char *filename = ident->toChars();
+    if (packages && packages->dim)
+    {
+        OutBuffer buf;
+        OutBuffer dotmods;
+        Array<const char *> *ms = global.params.modFileAliasStrings;
+        const size_t msdim = ms ? ms->dim : 0;
+
+        for (size_t i = 0; i < packages->dim; i++)
+        {
+            Identifier *pid = (*packages)[i];
+            const char *p = pid->toChars();
+            buf.writestring(p);
+            if (msdim)
+                checkModFileAlias(&buf, &dotmods, ms, msdim, p);
+#if _WIN32
+            buf.writeByte('\\');
+#else
+            buf.writeByte('/');
+#endif
+        }
+        buf.writestring(filename);
+        if (msdim)
+            checkModFileAlias(&buf, &dotmods, ms, msdim, filename);
+        buf.writeByte(0);
+        filename = (char *)buf.extractData();
+    }
+
+    Module *m = new Module(filename, ident, 0, 0);
+    m->loc = loc;
+
+    /* Look for the source file
+     */
+    const char *path;
+    const char *result = lookForSourceFile(&path, filename);
+    if (result)
+    {
+        m->srcfile = new File(result);
+        if (path)
+            m->srcfilePath = path;
+        else if (!FileName::absolute(result))
+            m->srcfilePath = getcwd(NULL, 0);
+    }
+
+    if (!m->read(loc))
+        return NULL;
+
+    if (global.params.verbose)
+    {
+        fprintf(global.stdmsg, "import    ");
+        if (packages)
+        {
+            for (size_t i = 0; i < packages->dim; i++)
+            {
+                Identifier *pid = (*packages)[i];
+                fprintf(global.stdmsg, "%s.", pid->toChars());
+            }
+        }
+        fprintf(global.stdmsg, "%s\t(%s)\n", ident->toChars(), m->srcfile->toChars());
+    }
+
+    m = m->parse();
+
+    Target::loadModule(m);
+
+    return m;
+}
+
+bool Module::read(Loc loc)
+{
+    //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars());
+    if (srcfile->read())
+    {
+        if (!strcmp(srcfile->toChars(), "object.d"))
+        {
+            ::error(loc, "cannot find source code for runtime library file 'object.d'");
+            errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions.");
+            errorSupplemental(loc, "config file: %s", FileName::canonicalName(global.inifilename));
+        }
+        else
+        {
+            // if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module
+            bool isPackageMod = (strcmp(toChars(), "package") != 0) &&
+                                (strcmp(srcfile->name->name(), "package.d") == 0);
+
+            if (isPackageMod)
+                ::error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'",
+                    toChars(), srcfile->toChars());
+            else
+                error(loc, "is in file '%s' which cannot be read", srcfile->toChars());
+        }
+
+        if (!global.gag)
+        {
+            /* Print path
+             */
+            if (global.path)
+            {
+                for (size_t i = 0; i < global.path->dim; i++)
+                {
+                    const char *p = (*global.path)[i];
+                    fprintf(stderr, "import path[%llu] = %s\n", (ulonglong)i, p);
+                }
+            }
+            else
+                fprintf(stderr, "Specify path to file '%s' with -I switch\n", srcfile->toChars());
+            fatal();
+        }
+        return false;
+    }
+    return true;
+}
+
+Module *Module::parse()
+{
+    //printf("Module::parse(srcfile='%s') this=%p\n", srcfile->name->toChars(), this);
+
+    const char *srcname = srcfile->name->toChars();
+    //printf("Module::parse(srcname = '%s')\n", srcname);
+
+    isPackageFile = (strcmp(srcfile->name->name(), "package.d") == 0);
+
+    utf8_t *buf = (utf8_t *)srcfile->buffer;
+    size_t buflen = srcfile->len;
+
+    if (buflen >= 2)
+    {
+        /* Convert all non-UTF-8 formats to UTF-8.
+         * BOM : http://www.unicode.org/faq/utf_bom.html
+         * 00 00 FE FF  UTF-32BE, big-endian
+         * FF FE 00 00  UTF-32LE, little-endian
+         * FE FF        UTF-16BE, big-endian
+         * FF FE        UTF-16LE, little-endian
+         * EF BB BF     UTF-8
+         */
+
+        unsigned le;
+        unsigned bom = 1;                // assume there's a BOM
+        if (buf[0] == 0xFF && buf[1] == 0xFE)
+        {
+            if (buflen >= 4 && buf[2] == 0 && buf[3] == 0)
+            {   // UTF-32LE
+                le = 1;
+
+            Lutf32:
+                OutBuffer dbuf;
+                unsigned *pu = (unsigned *)(buf);
+                unsigned *pumax = &pu[buflen / 4];
+
+                if (buflen & 3)
+                {   error("odd length of UTF-32 char source %u", buflen);
+                    fatal();
+                }
+
+                dbuf.reserve(buflen / 4);
+                for (pu += bom; pu < pumax; pu++)
+                {   unsigned u;
+
+                    u = le ? Port::readlongLE(pu) : Port::readlongBE(pu);
+                    if (u & ~0x7F)
+                    {
+                        if (u > 0x10FFFF)
+                        {   error("UTF-32 value %08x greater than 0x10FFFF", u);
+                            fatal();
+                        }
+                        dbuf.writeUTF8(u);
+                    }
+                    else
+                        dbuf.writeByte(u);
+                }
+                dbuf.writeByte(0);              // add 0 as sentinel for scanner
+                buflen = dbuf.offset - 1;       // don't include sentinel in count
+                buf = (utf8_t *) dbuf.extractData();
+            }
+            else
+            {   // UTF-16LE (X86)
+                // Convert it to UTF-8
+                le = 1;
+
+            Lutf16:
+                OutBuffer dbuf;
+                unsigned short *pu = (unsigned short *)(buf);
+                unsigned short *pumax = &pu[buflen / 2];
+
+                if (buflen & 1)
+                {   error("odd length of UTF-16 char source %u", buflen);
+                    fatal();
+                }
+
+                dbuf.reserve(buflen / 2);
+                for (pu += bom; pu < pumax; pu++)
+                {   unsigned u;
+
+                    u = le ? Port::readwordLE(pu) : Port::readwordBE(pu);
+                    if (u & ~0x7F)
+                    {   if (u >= 0xD800 && u <= 0xDBFF)
+                        {   unsigned u2;
+
+                            if (++pu > pumax)
+                            {   error("surrogate UTF-16 high value %04x at EOF", u);
+                                fatal();
+                            }
+                            u2 = le ? Port::readwordLE(pu) : Port::readwordBE(pu);
+                            if (u2 < 0xDC00 || u2 > 0xDFFF)
+                            {   error("surrogate UTF-16 low value %04x out of range", u2);
+                                fatal();
+                            }
+                            u = (u - 0xD7C0) << 10;
+                            u |= (u2 - 0xDC00);
+                        }
+                        else if (u >= 0xDC00 && u <= 0xDFFF)
+                        {   error("unpaired surrogate UTF-16 value %04x", u);
+                            fatal();
+                        }
+                        else if (u == 0xFFFE || u == 0xFFFF)
+                        {   error("illegal UTF-16 value %04x", u);
+                            fatal();
+                        }
+                        dbuf.writeUTF8(u);
+                    }
+                    else
+                        dbuf.writeByte(u);
+                }
+                dbuf.writeByte(0);              // add 0 as sentinel for scanner
+                buflen = dbuf.offset - 1;       // don't include sentinel in count
+                buf = (utf8_t *) dbuf.extractData();
+            }
+        }
+        else if (buf[0] == 0xFE && buf[1] == 0xFF)
+        {   // UTF-16BE
+            le = 0;
+            goto Lutf16;
+        }
+        else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF)
+        {   // UTF-32BE
+            le = 0;
+            goto Lutf32;
+        }
+        else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
+        {   // UTF-8
+
+            buf += 3;
+            buflen -= 3;
+        }
+        else
+        {
+            /* There is no BOM. Make use of Arcane Jill's insight that
+             * the first char of D source must be ASCII to
+             * figure out the encoding.
+             */
+
+            bom = 0;
+            if (buflen >= 4)
+            {   if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
+                {   // UTF-32LE
+                    le = 1;
+                    goto Lutf32;
+                }
+                else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0)
+                {   // UTF-32BE
+                    le = 0;
+                    goto Lutf32;
+                }
+            }
+            if (buflen >= 2)
+            {
+                if (buf[1] == 0)
+                {   // UTF-16LE
+                    le = 1;
+                    goto Lutf16;
+                }
+                else if (buf[0] == 0)
+                {   // UTF-16BE
+                    le = 0;
+                    goto Lutf16;
+                }
+            }
+
+            // It's UTF-8
+            if (buf[0] >= 0x80)
+            {   error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]);
+                fatal();
+            }
+        }
+    }
+
+    /* If it starts with the string "Ddoc", then it's a documentation
+     * source file.
+     */
+    if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0)
+    {
+        comment = buf + 4;
+        isDocFile = 1;
+        if (!docfile)
+            setDocfile();
+        return this;
+    }
+    {
+        Parser p(this, buf, buflen, docfile != NULL);
+        p.nextToken();
+        members = p.parseModule();
+        md = p.md;
+        numlines = p.scanloc.linnum;
+        if (p.errors)
+            ++global.errors;
+    }
+
+    if (srcfile->ref == 0)
+        ::free(srcfile->buffer);
+    srcfile->buffer = NULL;
+    srcfile->len = 0;
+
+    /* The symbol table into which the module is to be inserted.
+     */
+    DsymbolTable *dst;
+
+    if (md)
+    {
+        /* A ModuleDeclaration, md, was provided.
+         * The ModuleDeclaration sets the packages this module appears in, and
+         * the name of this module.
+         */
+        this->ident = md->id;
+        Package *ppack = NULL;
+        dst = Package::resolve(md->packages, &this->parent, &ppack);
+        assert(dst);
+
+        Module *m = ppack ? ppack->isModule() : NULL;
+        if (m && strcmp(m->srcfile->name->name(), "package.d") != 0)
+        {
+            ::error(md->loc, "package name '%s' conflicts with usage as a module name in file %s",
+                ppack->toPrettyChars(), m->srcfile->toChars());
+        }
+    }
+    else
+    {
+        /* The name of the module is set to the source file name.
+         * There are no packages.
+         */
+        dst = modules;          // and so this module goes into global module symbol table
+
+        /* Check to see if module name is a valid identifier
+         */
+        if (!Identifier::isValidIdentifier(this->ident->toChars()))
+            error("has non-identifier characters in filename, use module declaration instead");
+    }
+
+    // Add internal used functions in 'object' module members.
+    if (!parent && ident == Id::object)
+    {
+        static const utf8_t code_ArrayEq[] =
+            "bool _ArrayEq(T1, T2)(T1[] a, T2[] b) {\n"
+            " if (a.length != b.length) return false;\n"
+            " foreach (size_t i; 0 .. a.length) { if (a[i] != b[i]) return false; }\n"
+            " return true; }\n";
+
+        static const utf8_t code_ArrayPostblit[] =
+            "void _ArrayPostblit(T)(T[] a) { foreach (ref T e; a) e.__xpostblit(); }\n";
+
+        static const utf8_t code_ArrayDtor[] =
+            "void _ArrayDtor(T)(T[] a) { foreach_reverse (ref T e; a) e.__xdtor(); }\n";
+
+        static const utf8_t code_xopEquals[] =
+            "bool _xopEquals(in void*, in void*) { throw new Error(\"TypeInfo.equals is not implemented\"); }\n";
+
+        static const utf8_t code_xopCmp[] =
+            "bool _xopCmp(in void*, in void*) { throw new Error(\"TypeInfo.compare is not implemented\"); }\n";
+
+        Identifier *arreq = Id::_ArrayEq;
+        Identifier *xopeq = Identifier::idPool("_xopEquals");
+        Identifier *xopcmp = Identifier::idPool("_xopCmp");
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *sx = (*members)[i];
+            if (!sx) continue;
+            if (arreq && sx->ident == arreq) arreq = NULL;
+            if (xopeq && sx->ident == xopeq) xopeq = NULL;
+            if (xopcmp && sx->ident == xopcmp) xopcmp = NULL;
+        }
+
+        if (arreq)
+        {
+            Parser p(loc, this, code_ArrayEq, strlen((const char *)code_ArrayEq), 0);
+            p.nextToken();
+            members->append(p.parseDeclDefs(0));
+        }
+        {
+            Parser p(loc, this, code_ArrayPostblit, strlen((const char *)code_ArrayPostblit), 0);
+            p.nextToken();
+            members->append(p.parseDeclDefs(0));
+        }
+        {
+            Parser p(loc, this, code_ArrayDtor, strlen((const char *)code_ArrayDtor), 0);
+            p.nextToken();
+            members->append(p.parseDeclDefs(0));
+        }
+        if (xopeq)
+        {
+            Parser p(loc, this, code_xopEquals, strlen((const char *)code_xopEquals), 0);
+            p.nextToken();
+            members->append(p.parseDeclDefs(0));
+        }
+        if (xopcmp)
+        {
+            Parser p(loc, this, code_xopCmp, strlen((const char *)code_xopCmp), 0);
+            p.nextToken();
+            members->append(p.parseDeclDefs(0));
+        }
+    }
+
+    // Insert module into the symbol table
+    Dsymbol *s = this;
+    if (isPackageFile)
+    {
+        /* If the source tree is as follows:
+         *     pkg/
+         *     +- package.d
+         *     +- common.d
+         * the 'pkg' will be incorporated to the internal package tree in two ways:
+         *     import pkg;
+         * and:
+         *     import pkg.common;
+         *
+         * If both are used in one compilation, 'pkg' as a module (== pkg/package.d)
+         * and a package name 'pkg' will conflict each other.
+         *
+         * To avoid the conflict:
+         * 1. If preceding package name insertion had occurred by Package::resolve,
+         *    later package.d loading will change Package::isPkgMod to PKGmodule and set Package::mod.
+         * 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here.
+         */
+        Package *p = new Package(ident);
+        p->parent = this->parent;
+        p->isPkgMod = PKGmodule;
+        p->mod = this;
+        p->tag = this->tag; // reuse the same package tag
+        p->symtab = new DsymbolTable();
+        s = p;
+    }
+    if (!dst->insert(s))
+    {
+        /* It conflicts with a name that is already in the symbol table.
+         * Figure out what went wrong, and issue error message.
+         */
+        Dsymbol *prev = dst->lookup(ident);
+        assert(prev);
+        if (Module *mprev = prev->isModule())
+        {
+            if (FileName::compare(srcname, mprev->srcfile->toChars()) != 0)
+                error(loc, "from file %s conflicts with another module %s from file %s",
+                    srcname, mprev->toChars(), mprev->srcfile->toChars());
+            else if (isRoot() && mprev->isRoot())
+                error(loc, "from file %s is specified twice on the command line",
+                    srcname);
+            else
+                error(loc, "from file %s must be imported with 'import %s;'",
+                    srcname, toPrettyChars());
+
+            // Bugzilla 14446: Return previously parsed module to avoid AST duplication ICE.
+            return mprev;
+        }
+        else if (Package *pkg = prev->isPackage())
+        {
+            if (pkg->isPkgMod == PKGunknown && isPackageFile)
+            {
+                /* If the previous inserted Package is not yet determined as package.d,
+                 * link it to the actual module.
+                 */
+                pkg->isPkgMod = PKGmodule;
+                pkg->mod = this;
+                pkg->tag = this->tag; // reuse the same package tag
+            }
+            else
+                error(md ? md->loc : loc, "from file %s conflicts with package name %s",
+                    srcname, pkg->toChars());
+        }
+        else
+            assert(global.errors);
+    }
+    else
+    {
+        // Add to global array of all modules
+        amodules.push(this);
+    }
+    return this;
+}
+
+void Module::importAll(Scope *prevsc)
+{
+    //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+
+    if (_scope)
+        return;                 // already done
+
+    if (isDocFile)
+    {
+        error("is a Ddoc file, cannot import it");
+        return;
+    }
+
+    if (md && md->msg)
+    {
+        if (StringExp *se = md->msg->toStringExp())
+            md->msg = se;
+        else
+            md->msg->error("string expected, not '%s'", md->msg->toChars());
+    }
+
+    /* Note that modules get their own scope, from scratch.
+     * This is so regardless of where in the syntax a module
+     * gets imported, it is unaffected by context.
+     * Ignore prevsc.
+     */
+    Scope *sc = Scope::createGlobal(this);      // create root scope
+
+    // Add import of "object", even for the "object" module.
+    // If it isn't there, some compiler rewrites, like
+    //    classinst == classinst -> .object.opEquals(classinst, classinst)
+    // would fail inside object.d.
+    if (members->dim == 0 || ((*members)[0])->ident != Id::object)
+    {
+        Import *im = new Import(Loc(), NULL, Id::object, NULL, 0);
+        members->shift(im);
+    }
+
+    if (!symtab)
+    {
+        // Add all symbols into module's symbol table
+        symtab = new DsymbolTable();
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            s->addMember(sc, sc->scopesym);
+        }
+    }
+    // anything else should be run after addMember, so version/debug symbols are defined
+
+    /* Set scope for the symbols so that if we forward reference
+     * a symbol, it can possibly be resolved on the spot.
+     * If this works out well, it can be extended to all modules
+     * before any semantic() on any of them.
+     */
+    setScope(sc);               // remember module scope for semantic
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->setScope(sc);
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->importAll(sc);
+    }
+
+    sc = sc->pop();
+    sc->pop();          // 2 pops because Scope::createGlobal() created 2
+}
+
+void Module::semantic(Scope *)
+{
+    if (semanticRun != PASSinit)
+        return;
+
+    //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+    semanticRun = PASSsemantic;
+
+    // Note that modules get their own scope, from scratch.
+    // This is so regardless of where in the syntax a module
+    // gets imported, it is unaffected by context.
+    Scope *sc = _scope;                  // see if already got one from importAll()
+    if (!sc)
+    {
+        Scope::createGlobal(this);      // create root scope
+    }
+
+    //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage);
+
+    // Pass 1 semantic routines: do public side of the definition
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+
+        //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars());
+        s->semantic(sc);
+        runDeferredSemantic();
+    }
+
+    if (userAttribDecl)
+    {
+        userAttribDecl->semantic(sc);
+    }
+
+    if (!_scope)
+    {
+        sc = sc->pop();
+        sc->pop();              // 2 pops because Scope::createGlobal() created 2
+    }
+    semanticRun = PASSsemanticdone;
+    //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+}
+
+void Module::semantic2(Scope*)
+{
+    //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent);
+    if (semanticRun != PASSsemanticdone)       // semantic() not completed yet - could be recursive call
+        return;
+    semanticRun = PASSsemantic2;
+
+    // Note that modules get their own scope, from scratch.
+    // This is so regardless of where in the syntax a module
+    // gets imported, it is unaffected by context.
+    Scope *sc = Scope::createGlobal(this);      // create root scope
+    //printf("Module = %p\n", sc.scopesym);
+
+    // Pass 2 semantic routines: do initializers and function bodies
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->semantic2(sc);
+    }
+
+    if (userAttribDecl)
+    {
+        userAttribDecl->semantic2(sc);
+    }
+
+    sc = sc->pop();
+    sc->pop();
+    semanticRun = PASSsemantic2done;
+    //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent);
+}
+
+void Module::semantic3(Scope*)
+{
+    //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent);
+    if (semanticRun != PASSsemantic2done)
+        return;
+    semanticRun = PASSsemantic3;
+
+    // Note that modules get their own scope, from scratch.
+    // This is so regardless of where in the syntax a module
+    // gets imported, it is unaffected by context.
+    Scope *sc = Scope::createGlobal(this);      // create root scope
+    //printf("Module = %p\n", sc.scopesym);
+
+    // Pass 3 semantic routines: do initializers and function bodies
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        //printf("Module %s: %s.semantic3()\n", toChars(), s->toChars());
+        s->semantic3(sc);
+
+        runDeferredSemantic2();
+    }
+
+    if (userAttribDecl)
+    {
+        userAttribDecl->semantic3(sc);
+    }
+
+    sc = sc->pop();
+    sc->pop();
+    semanticRun = PASSsemantic3done;
+}
+
+/**********************************
+ * Determine if we need to generate an instance of ModuleInfo
+ * for this Module.
+ */
+
+int Module::needModuleInfo()
+{
+    //printf("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov);
+    return needmoduleinfo || global.params.cov;
+}
+
+Dsymbol *Module::search(Loc loc, Identifier *ident, int flags)
+{
+    /* Since modules can be circularly referenced,
+     * need to stop infinite recursive searches.
+     * This is done with the cache.
+     */
+
+    //printf("%s Module::search('%s', flags = x%x) insearch = %d\n", toChars(), ident->toChars(), flags, insearch);
+    if (insearch)
+        return NULL;
+
+    /* Qualified module searches always search their imports,
+     * even if SearchLocalsOnly
+     */
+    if (!(flags & SearchUnqualifiedModule))
+        flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly);
+
+    if (searchCacheIdent == ident && searchCacheFlags == flags)
+    {
+        //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n",
+        //        toChars(), ident->toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol->toChars() : "null");
+        return searchCacheSymbol;
+    }
+
+    unsigned int errors = global.errors;
+
+    insearch = 1;
+    Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
+    insearch = 0;
+
+    if (errors == global.errors)
+    {
+        // Bugzilla 10752: We can cache the result only when it does not cause
+        // access error so the side-effect should be reproduced in later search.
+        searchCacheIdent = ident;
+        searchCacheSymbol = s;
+        searchCacheFlags = flags;
+    }
+    return s;
+}
+
+bool Module::isPackageAccessible(Package *p, Prot protection, int flags)
+{
+    if (insearch) // don't follow import cycles
+        return false;
+    if (flags & IgnorePrivateImports)
+        protection = Prot(PROTpublic); // only consider public imports
+    insearch = true;
+    bool r = ScopeDsymbol::isPackageAccessible(p, protection);
+    insearch = false;
+    return r;
+}
+
+Dsymbol *Module::symtabInsert(Dsymbol *s)
+{
+    searchCacheIdent = NULL;       // symbol is inserted, so invalidate cache
+    return Package::symtabInsert(s);
+}
+
+void Module::clearCache()
+{
+    for (size_t i = 0; i < amodules.dim; i++)
+    {
+        Module *m = amodules[i];
+        m->searchCacheIdent = NULL;
+    }
+}
+
+/*******************************************
+ * Can't run semantic on s now, try again later.
+ */
+
+void Module::addDeferredSemantic(Dsymbol *s)
+{
+    // Don't add it if it is already there
+    for (size_t i = 0; i < deferred.dim; i++)
+    {
+        Dsymbol *sd = deferred[i];
+
+        if (sd == s)
+            return;
+    }
+
+    //printf("Module::addDeferredSemantic('%s')\n", s->toChars());
+    deferred.push(s);
+}
+
+void Module::addDeferredSemantic2(Dsymbol *s)
+{
+    //printf("Module::addDeferredSemantic2('%s')\n", s->toChars());
+    deferred2.push(s);
+}
+
+void Module::addDeferredSemantic3(Dsymbol *s)
+{
+    //printf("Module::addDeferredSemantic3('%s')\n", s->toChars());
+    deferred3.push(s);
+}
+
+/******************************************
+ * Run semantic() on deferred symbols.
+ */
+
+void Module::runDeferredSemantic()
+{
+    if (dprogress == 0)
+        return;
+
+    static int nested;
+    if (nested)
+        return;
+    //if (deferred.dim) printf("+Module::runDeferredSemantic(), len = %d\n", deferred.dim);
+    nested++;
+
+    size_t len;
+    do
+    {
+        dprogress = 0;
+        len = deferred.dim;
+        if (!len)
+            break;
+
+        Dsymbol **todo;
+        Dsymbol **todoalloc = NULL;
+        Dsymbol *tmp;
+        if (len == 1)
+        {
+            todo = &tmp;
+        }
+        else
+        {
+            todo = (Dsymbol **)malloc(len * sizeof(Dsymbol *));
+            assert(todo);
+            todoalloc = todo;
+        }
+        memcpy(todo, deferred.tdata(), len * sizeof(Dsymbol *));
+        deferred.setDim(0);
+
+        for (size_t i = 0; i < len; i++)
+        {
+            Dsymbol *s = todo[i];
+
+            s->semantic(NULL);
+            //printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars());
+        }
+        //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress);
+        if (todoalloc)
+            free(todoalloc);
+    } while (deferred.dim < len || dprogress);  // while making progress
+    nested--;
+    //printf("-Module::runDeferredSemantic(), len = %d\n", deferred.dim);
+}
+
+void Module::runDeferredSemantic2()
+{
+    Module::runDeferredSemantic();
+
+    Dsymbols *a = &Module::deferred2;
+    for (size_t i = 0; i < a->dim; i++)
+    {
+        Dsymbol *s = (*a)[i];
+        //printf("[%d] %s semantic2a\n", i, s->toPrettyChars());
+        s->semantic2(NULL);
+
+        if (global.errors)
+            break;
+    }
+    a->setDim(0);
+}
+
+void Module::runDeferredSemantic3()
+{
+    Module::runDeferredSemantic2();
+
+    Dsymbols *a = &Module::deferred3;
+    for (size_t i = 0; i < a->dim; i++)
+    {
+        Dsymbol *s = (*a)[i];
+        //printf("[%d] %s semantic3a\n", i, s->toPrettyChars());
+
+        s->semantic3(NULL);
+
+        if (global.errors)
+            break;
+    }
+    a->setDim(0);
+}
+
+/************************************
+ * Recursively look at every module this module imports,
+ * return true if it imports m.
+ * Can be used to detect circular imports.
+ */
+
+int Module::imports(Module *m)
+{
+    //printf("%s Module::imports(%s)\n", toChars(), m->toChars());
+#if 0
+    for (size_t i = 0; i < aimports.dim; i++)
+    {
+        Module *mi = (Module *)aimports.data[i];
+        printf("\t[%d] %s\n", i, mi->toChars());
+    }
+#endif
+    for (size_t i = 0; i < aimports.dim; i++)
+    {
+        Module *mi = aimports[i];
+        if (mi == m)
+            return true;
+        if (!mi->insearch)
+        {
+            mi->insearch = 1;
+            int r = mi->imports(m);
+            if (r)
+                return r;
+        }
+    }
+    return false;
+}
+
+/*************************************
+ * Return true if module imports itself.
+ */
+
+bool Module::selfImports()
+{
+    //printf("Module::selfImports() %s\n", toChars());
+    if (selfimports == 0)
+    {
+        for (size_t i = 0; i < amodules.dim; i++)
+            amodules[i]->insearch = 0;
+
+        selfimports = imports(this) + 1;
+
+        for (size_t i = 0; i < amodules.dim; i++)
+            amodules[i]->insearch = 0;
+    }
+    return selfimports == 2;
+}
+
+/*************************************
+ * Return true if module imports root module.
+ */
+
+bool Module::rootImports()
+{
+    //printf("Module::rootImports() %s\n", toChars());
+    if (rootimports == 0)
+    {
+        for (size_t i = 0; i < amodules.dim; i++)
+            amodules[i]->insearch = 0;
+
+        rootimports = 1;
+        for (size_t i = 0; i < amodules.dim; ++i)
+        {
+            Module *m = amodules[i];
+            if (m->isRoot() && imports(m))
+            {
+                rootimports = 2;
+                break;
+            }
+        }
+
+        for (size_t i = 0; i < amodules.dim; i++)
+            amodules[i]->insearch = 0;
+    }
+    return rootimports == 2;
+}
+
+bool Module::isCoreModule(Identifier *ident)
+{
+    return this->ident == ident && parent && parent->ident == Id::core && !parent->parent;
+}
+
+/* =========================== ModuleDeclaration ===================== */
+
+ModuleDeclaration::ModuleDeclaration(Loc loc, Identifiers *packages, Identifier *id)
+{
+    this->loc = loc;
+    this->packages = packages;
+    this->id = id;
+    this->isdeprecated = false;
+    this->msg = NULL;
+}
+
+const char *ModuleDeclaration::toChars()
+{
+    OutBuffer buf;
+
+    if (packages && packages->dim)
+    {
+        for (size_t i = 0; i < packages->dim; i++)
+        {
+            Identifier *pid = (*packages)[i];
+            buf.writestring(pid->toChars());
+            buf.writeByte('.');
+        }
+    }
+    buf.writestring(id->toChars());
+    return buf.extractString();
+}
+
+/* =========================== Package ===================== */
+
+Package::Package(Identifier *ident)
+        : ScopeDsymbol(ident)
+{
+    this->isPkgMod = PKGunknown;
+    this->mod = NULL;
+    static unsigned packageTag = 0;
+    this->tag = packageTag++;
+}
+
+
+const char *Package::kind()
+{
+    return "package";
+}
+
+Module *Package::isPackageMod()
+{
+    if (isPkgMod == PKGmodule)
+    {
+        return mod;
+    }
+    return NULL;
+}
+
+/**
+ * Checks if pkg is a sub-package of this
+ *
+ * For example, if this qualifies to 'a1.a2' and pkg - to 'a1.a2.a3',
+ * this function returns 'true'. If it is other way around or qualified
+ * package paths conflict function returns 'false'.
+ *
+ * Params:
+ *  pkg = possible subpackage
+ *
+ * Returns:
+ *  see description
+ */
+bool Package::isAncestorPackageOf(const Package * const pkg) const
+{
+    if (this == pkg)
+        return true;
+    if (!pkg || !pkg->parent)
+        return false;
+    return isAncestorPackageOf(pkg->parent->isPackage());
+}
+
+/****************************************************
+ * Input:
+ *      packages[]      the pkg1.pkg2 of pkg1.pkg2.mod
+ * Returns:
+ *      the symbol table that mod should be inserted into
+ * Output:
+ *      *pparent        the rightmost package, i.e. pkg2, or NULL if no packages
+ *      *ppkg           the leftmost package, i.e. pkg1, or NULL if no packages
+ */
+
+DsymbolTable *Package::resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg)
+{
+    DsymbolTable *dst = Module::modules;
+    Dsymbol *parent = NULL;
+
+    //printf("Package::resolve()\n");
+    if (ppkg)
+        *ppkg = NULL;
+
+    if (packages)
+    {
+        for (size_t i = 0; i < packages->dim; i++)
+        {
+            Identifier *pid = (*packages)[i];
+            Package *pkg;
+            Dsymbol *p = dst->lookup(pid);
+            if (!p)
+            {
+                pkg = new Package(pid);
+                dst->insert(pkg);
+                pkg->parent = parent;
+                pkg->symtab = new DsymbolTable();
+            }
+            else
+            {
+                pkg = p->isPackage();
+                assert(pkg);
+                // It might already be a module, not a package, but that needs
+                // to be checked at a higher level, where a nice error message
+                // can be generated.
+                // dot net needs modules and packages with same name
+
+                // But we still need a symbol table for it
+                if (!pkg->symtab)
+                    pkg->symtab = new DsymbolTable();
+            }
+            parent = pkg;
+            dst = pkg->symtab;
+            if (ppkg && !*ppkg)
+                *ppkg = pkg;
+            if (pkg->isModule())
+            {
+                // Return the module so that a nice error message can be generated
+                if (ppkg)
+                    *ppkg = (Package *)p;
+                break;
+            }
+        }
+    }
+    if (pparent)
+        *pparent = parent;
+    return dst;
+}
+
+Dsymbol *Package::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("%s Package::search('%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
+    flags &= ~SearchLocalsOnly;  // searching an import is always transitive
+    if (!isModule() && mod)
+    {
+        // Prefer full package name.
+        Dsymbol *s = symtab ? symtab->lookup(ident) : NULL;
+        if (s)
+            return s;
+        //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars());
+        return mod->search(loc, ident, flags);
+    }
+
+    return ScopeDsymbol::search(loc, ident, flags);
+}
+
+/* ===========================  ===================== */
+
+/********************************************
+ * Look for the source file if it's different from filename.
+ * Look for .di, .d, directory, and along global.path.
+ * Does not open the file.
+ * Output:
+ *      path            the path where the file was found if it was not the current directory
+ * Input:
+ *      filename        as supplied by the user
+ *      global.path
+ * Returns:
+ *      NULL if it's not different from filename.
+ */
+
+const char *lookForSourceFile(const char **path, const char *filename)
+{
+    /* Search along global.path for .di file, then .d file.
+     */
+    *path = NULL;
+
+    const char *sdi = FileName::forceExt(filename, global.hdr_ext);
+    if (FileName::exists(sdi) == 1)
+        return sdi;
+
+    const char *sd  = FileName::forceExt(filename, global.mars_ext);
+    if (FileName::exists(sd) == 1)
+        return sd;
+
+    if (FileName::exists(filename) == 2)
+    {
+        /* The filename exists and it's a directory.
+         * Therefore, the result should be: filename/package.d
+         * iff filename/package.d is a file
+         */
+        const char *n = FileName::combine(filename, "package.d");
+        if (FileName::exists(n) == 1)
+            return n;
+        FileName::free(n);
+    }
+
+    if (FileName::absolute(filename))
+        return NULL;
+
+    if (!global.path)
+        return NULL;
+
+    for (size_t i = 0; i < global.path->dim; i++)
+    {
+        const char *p = (*global.path)[i];
+
+        const char *n = FileName::combine(p, sdi);
+        if (FileName::exists(n) == 1)
+        {
+            *path = p;
+            return n;
+        }
+        FileName::free(n);
+
+        n = FileName::combine(p, sd);
+        if (FileName::exists(n) == 1)
+        {
+            *path = p;
+            return n;
+        }
+        FileName::free(n);
+
+        const char *b = FileName::removeExt(filename);
+        n = FileName::combine(p, b);
+        FileName::free(b);
+        if (FileName::exists(n) == 2)
+        {
+            const char *n2 = FileName::combine(n, "package.d");
+            if (FileName::exists(n2) == 1)
+            {
+                *path = p;
+                return n2;
+            }
+            FileName::free(n2);
+        }
+        FileName::free(n);
+    }
+    return NULL;
+}
diff --git a/gcc/d/dfrontend/doc.c b/gcc/d/dfrontend/doc.c
new file mode 100644
index 00000000000..a8cabe9d5b8
--- /dev/null
+++ b/gcc/d/dfrontend/doc.c
@@ -0,0 +1,2803 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/doc.c
+ */
+
+// This implements the Ddoc capability.
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "rmem.h"
+#include "root.h"
+#include "port.h"
+#include "aav.h"
+
+#include "attrib.h"
+#include "cond.h"
+#include "mars.h"
+#include "dsymbol.h"
+#include "macro.h"
+#include "template.h"
+#include "lexer.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "statement.h"
+#include "enum.h"
+#include "id.h"
+#include "module.h"
+#include "scope.h"
+#include "hdrgen.h"
+#include "doc.h"
+#include "mtype.h"
+#include "utf.h"
+
+void emitMemberComments(ScopeDsymbol *sds, OutBuffer *buf, Scope *sc);
+void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc);
+void emitComment(Dsymbol *s, OutBuffer *buf, Scope *sc);
+
+struct Escape
+{
+    const char *strings[256];
+
+    const char *escapeChar(unsigned c);
+};
+
+class Section
+{
+public:
+    const utf8_t *name;
+    size_t namelen;
+
+    const utf8_t *body;
+    size_t bodylen;
+
+    int nooutput;
+
+    virtual void write(Loc loc, DocComment *dc, Scope *sc, Dsymbols *a, OutBuffer *buf);
+};
+
+class ParamSection : public Section
+{
+public:
+    void write(Loc loc, DocComment *dc, Scope *sc, Dsymbols *a, OutBuffer *buf);
+};
+
+class MacroSection : public Section
+{
+public:
+    void write(Loc loc, DocComment *dc, Scope *sc, Dsymbols *a, OutBuffer *buf);
+};
+
+typedef Array<Section *> Sections;
+
+struct DocComment
+{
+    Sections sections;             // Section*[]
+
+    Section *summary;
+    Section *copyright;
+    Section *macros;
+    Macro **pmacrotable;
+    Escape **pescapetable;
+
+    Dsymbols a;
+
+    DocComment() :
+       summary(NULL), copyright(NULL), macros(NULL), pmacrotable(NULL), pescapetable(NULL)
+    { }
+
+    static DocComment *parse(Scope *sc, Dsymbol *s, const utf8_t *comment);
+    static void parseMacros(Escape **pescapetable, Macro **pmacrotable, const utf8_t *m, size_t mlen);
+    static void parseEscapes(Escape **pescapetable, const utf8_t *textstart, size_t textlen);
+
+    void parseSections(const utf8_t *comment);
+    void writeSections(Scope *sc, Dsymbols *a, OutBuffer *buf);
+};
+
+
+int cmp(const char *stringz, const void *s, size_t slen);
+int icmp(const char *stringz, const void *s, size_t slen);
+bool isDitto(const utf8_t *comment);
+const utf8_t *skipwhitespace(const utf8_t *p);
+size_t skiptoident(OutBuffer *buf, size_t i);
+size_t skippastident(OutBuffer *buf, size_t i);
+size_t skippastURL(OutBuffer *buf, size_t i);
+void highlightText(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset);
+void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset);
+void highlightCode(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset);
+void highlightCode2(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset);
+void highlightCode3(Scope *sc, OutBuffer *buf, const utf8_t *p, const utf8_t *pend);
+TypeFunction *isTypeFunction(Dsymbol *s);
+Parameter *isFunctionParameter(Dsymbols *a, const utf8_t *p, size_t len);
+TemplateParameter *isTemplateParameter(Dsymbols *a, const utf8_t *p, size_t len);
+
+bool isIdStart(const utf8_t *p);
+bool isCVariadicArg(const utf8_t *p, size_t len);
+bool isIdTail(const utf8_t *p);
+bool isIndentWS(const utf8_t *p);
+int utfStride(const utf8_t *p);
+
+// Workaround for missing Parameter instance for variadic params. (it's unnecessary to instantiate one).
+bool isCVariadicParameter(Dsymbols *a, const utf8_t *p, size_t len)
+{
+    for (size_t i = 0; i < a->dim; i++)
+    {
+        TypeFunction *tf = isTypeFunction((*a)[i]);
+        if (tf && tf->varargs == 1 && cmp("...", p, len) == 0)
+            return true;
+    }
+    return false;
+}
+
+static Dsymbol *getEponymousMember(TemplateDeclaration *td)
+{
+    if (!td->onemember)
+        return NULL;
+
+    if (AggregateDeclaration *ad = td->onemember->isAggregateDeclaration())
+        return ad;
+    if (FuncDeclaration *fd = td->onemember->isFuncDeclaration())
+        return fd;
+    if (EnumMember *em = td->onemember->isEnumMember())
+        return NULL;    // Keep backward compatibility. See compilable/ddoc9.d
+    if (VarDeclaration *vd = td->onemember->isVarDeclaration())
+        return td->constraint ? NULL : vd;
+
+    return NULL;
+}
+
+static TemplateDeclaration *getEponymousParent(Dsymbol *s)
+{
+    if (!s->parent)
+        return NULL;
+    TemplateDeclaration *td = s->parent->isTemplateDeclaration();
+    return (td && getEponymousMember(td)) ? td : NULL;
+}
+
+static const char ddoc_default[] = "\
+DDOC =  <html><head>\n\
+        <META http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n\
+        <title>$(TITLE)</title>\n\
+        </head><body>\n\
+        <h1>$(TITLE)</h1>\n\
+        $(BODY)\n\
+        <hr>$(SMALL Page generated by $(LINK2 http://dlang.org/ddoc.html, Ddoc). $(COPYRIGHT))\n\
+        </body></html>\n\
+\n\
+B =     <b>$0</b>\n\
+I =     <i>$0</i>\n\
+U =     <u>$0</u>\n\
+P =     <p>$0</p>\n\
+DL =    <dl>$0</dl>\n\
+DT =    <dt>$0</dt>\n\
+DD =    <dd>$0</dd>\n\
+TABLE = <table>$0</table>\n\
+TR =    <tr>$0</tr>\n\
+TH =    <th>$0</th>\n\
+TD =    <td>$0</td>\n\
+OL =    <ol>$0</ol>\n\
+UL =    <ul>$0</ul>\n\
+LI =    <li>$0</li>\n\
+BIG =   <big>$0</big>\n\
+SMALL = <small>$0</small>\n\
+BR =    <br>\n\
+LINK =  <a href=\"$0\">$0</a>\n\
+LINK2 = <a href=\"$1\">$+</a>\n\
+LPAREN= (\n\
+RPAREN= )\n\
+BACKTICK= `\n\
+DOLLAR= $\n\
+DEPRECATED= $0\n\
+\n\
+RED =   <font color=red>$0</font>\n\
+BLUE =  <font color=blue>$0</font>\n\
+GREEN = <font color=green>$0</font>\n\
+YELLOW =<font color=yellow>$0</font>\n\
+BLACK = <font color=black>$0</font>\n\
+WHITE = <font color=white>$0</font>\n\
+\n\
+D_CODE = <pre class=\"d_code\">$0</pre>\n\
+DDOC_BACKQUOTED = $(D_INLINECODE $0)\n\
+D_INLINECODE = <pre style=\"display:inline;\" class=\"d_inline_code\">$0</pre>\n\
+D_COMMENT = $(GREEN $0)\n\
+D_STRING  = $(RED $0)\n\
+D_KEYWORD = $(BLUE $0)\n\
+D_PSYMBOL = $(U $0)\n\
+D_PARAM   = $(I $0)\n\
+\n\
+DDOC_COMMENT   = <!-- $0 -->\n\
+DDOC_DECL      = $(DT $(BIG $0))\n\
+DDOC_DECL_DD   = $(DD $0)\n\
+DDOC_DITTO     = $(BR)$0\n\
+DDOC_SECTIONS  = $0\n\
+DDOC_SUMMARY   = $0$(BR)$(BR)\n\
+DDOC_DESCRIPTION = $0$(BR)$(BR)\n\
+DDOC_AUTHORS   = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_BUGS      = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_DATE      = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_EXAMPLES  = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_HISTORY   = $(B History:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_LICENSE   = $(B License:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_RETURNS   = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_SEE_ALSO  = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_THROWS    = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_VERSION   = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_SECTION_H = $(B $0)$(BR)\n\
+DDOC_SECTION   = $0$(BR)$(BR)\n\
+DDOC_MEMBERS   = $(DL $0)\n\
+DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\
+DDOC_CLASS_MEMBERS  = $(DDOC_MEMBERS $0)\n\
+DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\
+DDOC_ENUM_MEMBERS   = $(DDOC_MEMBERS $0)\n\
+DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\
+DDOC_ENUM_BASETYPE = $0\n\
+DDOC_PARAMS    = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\
+DDOC_PARAM_ROW = $(TR $0)\n\
+DDOC_PARAM_ID  = $(TD $0)\n\
+DDOC_PARAM_DESC = $(TD $0)\n\
+DDOC_BLANKLINE  = $(BR)$(BR)\n\
+\n\
+DDOC_ANCHOR     = <a name=\"$1\"></a>\n\
+DDOC_PSYMBOL    = $(U $0)\n\
+DDOC_PSUPER_SYMBOL = $(U $0)\n\
+DDOC_KEYWORD    = $(B $0)\n\
+DDOC_PARAM      = $(I $0)\n\
+\n\
+ESCAPES = /</&lt;/\n\
+          />/&gt;/\n\
+          /&/&amp;/\n\
+";
+
+static const char ddoc_decl_s[] = "$(DDOC_DECL ";
+static const char ddoc_decl_e[] = ")\n";
+
+static const char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD ";
+static const char ddoc_decl_dd_e[] = ")\n";
+
+
+/****************************************************
+ */
+
+void gendocfile(Module *m)
+{
+    static OutBuffer mbuf;
+    static int mbuf_done;
+
+    OutBuffer buf;
+
+    //printf("Module::gendocfile()\n");
+
+    if (!mbuf_done)             // if not already read the ddoc files
+    {
+        mbuf_done = 1;
+
+        // Use our internal default
+        mbuf.write(ddoc_default, strlen(ddoc_default));
+
+        // Override with DDOCFILE specified in the sc.ini file
+        char *p = getenv("DDOCFILE");
+        if (p)
+            global.params.ddocfiles->shift(p);
+
+        // Override with the ddoc macro files from the command line
+        for (size_t i = 0; i < global.params.ddocfiles->dim; i++)
+        {
+            FileName f((*global.params.ddocfiles)[i]);
+            File file(&f);
+            readFile(m->loc, &file);
+            // BUG: convert file contents to UTF-8 before use
+
+            //printf("file: '%.*s'\n", file.len, file.buffer);
+            mbuf.write(file.buffer, file.len);
+        }
+    }
+    DocComment::parseMacros(&m->escapetable, &m->macrotable, (utf8_t *)mbuf.data, mbuf.offset);
+
+    Scope *sc = Scope::createGlobal(m);      // create root scope
+
+    DocComment *dc = DocComment::parse(sc, m, m->comment);
+    dc->pmacrotable = &m->macrotable;
+    dc->pescapetable = &m->escapetable;
+    sc->lastdc = dc;
+
+    // Generate predefined macros
+
+    // Set the title to be the name of the module
+    {
+        const char *p = m->toPrettyChars();
+        Macro::define(&m->macrotable, (utf8_t *)"TITLE", 5, (utf8_t *)p, strlen(p));
+    }
+
+    // Set time macros
+    {
+        time_t t;
+        time(&t);
+        char *p = ctime(&t);
+        p = mem.xstrdup(p);
+        Macro::define(&m->macrotable, (utf8_t *)"DATETIME", 8, (utf8_t *)p, strlen(p));
+        Macro::define(&m->macrotable, (utf8_t *)"YEAR", 4, (utf8_t *)p + 20, 4);
+    }
+
+    const char *srcfilename = m->srcfile->toChars();
+    Macro::define(&m->macrotable, (utf8_t *)"SRCFILENAME", 11, (utf8_t *)srcfilename, strlen(srcfilename));
+
+    const char *docfilename = m->docfile->toChars();
+    Macro::define(&m->macrotable, (utf8_t *)"DOCFILENAME", 11, (utf8_t *)docfilename, strlen(docfilename));
+
+    if (dc->copyright)
+    {
+        dc->copyright->nooutput = 1;
+        Macro::define(&m->macrotable, (utf8_t *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen);
+    }
+
+    buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", m->srcfile->toChars());
+    if (m->isDocFile)
+    {
+        Loc loc = m->md ? m->md->loc : m->loc;
+        size_t commentlen = strlen((char *)m->comment);
+        Dsymbols a;
+        // Bugzilla 9764: Don't push m in a, to prevent emphasize ddoc file name.
+        if (dc->macros)
+        {
+            commentlen = dc->macros->name - m->comment;
+            dc->macros->write(loc, dc, sc, &a, &buf);
+        }
+        buf.write(m->comment, commentlen);
+        highlightText(sc, &a, &buf, 0);
+    }
+    else
+    {
+        Dsymbols a;
+        a.push(m);
+        dc->writeSections(sc, &a, &buf);
+        emitMemberComments(m, &buf, sc);
+    }
+
+    //printf("BODY= '%.*s'\n", buf.offset, buf.data);
+    Macro::define(&m->macrotable, (utf8_t *)"BODY", 4, (utf8_t *)buf.data, buf.offset);
+
+    OutBuffer buf2;
+    buf2.writestring("$(DDOC)\n");
+    size_t end = buf2.offset;
+    m->macrotable->expand(&buf2, 0, &end, NULL, 0);
+
+#if 1
+    /* Remove all the escape sequences from buf2,
+     * and make CR-LF the newline.
+     */
+    {
+        buf.setsize(0);
+        buf.reserve(buf2.offset);
+        utf8_t *p = (utf8_t *)buf2.data;
+        for (size_t j = 0; j < buf2.offset; j++)
+        {
+            utf8_t c = p[j];
+            if (c == 0xFF && j + 1 < buf2.offset)
+            {
+                j++;
+                continue;
+            }
+            if (c == '\n')
+                buf.writeByte('\r');
+            else if (c == '\r')
+            {
+                buf.writestring("\r\n");
+                if (j + 1 < buf2.offset && p[j + 1] == '\n')
+                {
+                    j++;
+                }
+                continue;
+            }
+            buf.writeByte(c);
+        }
+    }
+
+    // Transfer image to file
+    assert(m->docfile);
+    m->docfile->setbuffer(buf.data, buf.offset);
+    m->docfile->ref = 1;
+    ensurePathToNameExists(Loc(), m->docfile->toChars());
+    writeFile(m->loc, m->docfile);
+#else
+    /* Remove all the escape sequences from buf2
+     */
+    {
+        size_t i = 0;
+        utf8_t *p = buf2.data;
+        for (size_t j = 0; j < buf2.offset; j++)
+        {
+            if (p[j] == 0xFF && j + 1 < buf2.offset)
+            {
+                j++;
+                continue;
+            }
+            p[i] = p[j];
+            i++;
+        }
+        buf2.setsize(i);
+    }
+
+    // Transfer image to file
+    m->docfile->setbuffer(buf2.data, buf2.offset);
+    m->docfile->ref = 1;
+    ensurePathToNameExists(Loc(), m->docfile->toChars());
+    writeFile(m->loc, m->docfile);
+#endif
+}
+
+/****************************************************
+ * Having unmatched parentheses can hose the output of Ddoc,
+ * as the macros depend on properly nested parentheses.
+ * This function replaces all ( with $(LPAREN) and ) with $(RPAREN)
+ * to preserve text literally. This also means macros in the
+ * text won't be expanded.
+ */
+void escapeDdocString(OutBuffer *buf, size_t start)
+{
+    for (size_t u = start; u < buf->offset; u++)
+    {
+        utf8_t c = buf->data[u];
+        switch(c)
+        {
+            case '$':
+                buf->remove(u, 1);
+                buf->insert(u, (const char *)"$(DOLLAR)", 9);
+                u += 8;
+                break;
+
+            case '(':
+                buf->remove(u, 1); //remove the (
+                buf->insert(u, (const char *)"$(LPAREN)", 9); //insert this instead
+                u += 8; //skip over newly inserted macro
+                break;
+
+            case ')':
+                buf->remove(u, 1); //remove the )
+                buf->insert(u, (const char *)"$(RPAREN)", 9); //insert this instead
+                u += 8; //skip over newly inserted macro
+                break;
+        }
+    }
+}
+
+/****************************************************
+ * Having unmatched parentheses can hose the output of Ddoc,
+ * as the macros depend on properly nested parentheses.
+
+ * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN).
+ */
+void escapeStrayParenthesis(Loc loc, OutBuffer *buf, size_t start)
+{
+    unsigned par_open = 0;
+
+    for (size_t u = start; u < buf->offset; u++)
+    {
+        utf8_t c = buf->data[u];
+        switch(c)
+        {
+            case '(':
+                par_open++;
+                break;
+
+            case ')':
+                if (par_open == 0)
+                {
+                    //stray ')'
+                    warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output."
+                        " Use $(RPAREN) instead for unpaired right parentheses.");
+                    buf->remove(u, 1); //remove the )
+                    buf->insert(u, (const char *)"$(RPAREN)", 9); //insert this instead
+                    u += 8; //skip over newly inserted macro
+                }
+                else
+                    par_open--;
+                break;
+#if 0
+            // For this to work, loc must be set to the beginning of the passed
+            // text which is currently not possible
+            // (loc is set to the Loc of the Dsymbol)
+            case '\n':
+                loc.linnum++;
+                break;
+#endif
+        }
+    }
+
+    if (par_open)                       // if any unmatched lparens
+    {
+        par_open = 0;
+        for (size_t u = buf->offset; u > start;)
+        {
+            u--;
+            utf8_t c = buf->data[u];
+            switch(c)
+            {
+                case ')':
+                    par_open++;
+                    break;
+
+                case '(':
+                    if (par_open == 0)
+                    {
+                        //stray '('
+                        warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output."
+                            " Use $(LPAREN) instead for unpaired left parentheses.");
+                        buf->remove(u, 1); //remove the (
+                        buf->insert(u, (const char *)"$(LPAREN)", 9); //insert this instead
+                    }
+                    else
+                        par_open--;
+                    break;
+            }
+        }
+    }
+}
+
+// Basically, this is to skip over things like private{} blocks in a struct or
+// class definition that don't add any components to the qualified name.
+static Scope *skipNonQualScopes(Scope *sc)
+{
+    while (sc && !sc->scopesym)
+        sc = sc->enclosing;
+    return sc;
+}
+
+static bool emitAnchorName(OutBuffer *buf, Dsymbol *s, Scope *sc)
+{
+    if (!s || s->isPackage() || s->isModule())
+        return false;
+
+    // Add parent names first
+    bool dot = false;
+    if (s->parent)
+        dot = emitAnchorName(buf, s->parent, sc);
+    else if (sc)
+        dot = emitAnchorName(buf, sc->scopesym, skipNonQualScopes(sc->enclosing));
+
+    // Eponymous template members can share the parent anchor name
+    if (getEponymousParent(s))
+        return dot;
+    if (dot)
+        buf->writeByte('.');
+
+    // Use "this" not "__ctor"
+    TemplateDeclaration *td;
+    if (s->isCtorDeclaration() || ((td = s->isTemplateDeclaration()) != NULL &&
+        td->onemember && td->onemember->isCtorDeclaration()))
+    {
+        buf->writestring("this");
+    }
+    else
+    {
+        /* We just want the identifier, not overloads like TemplateDeclaration::toChars.
+         * We don't want the template parameter list and constraints. */
+        buf->writestring(s->Dsymbol::toChars());
+    }
+    return true;
+}
+
+static void emitAnchor(OutBuffer *buf, Dsymbol *s, Scope *sc)
+{
+    Identifier *ident;
+    {
+        OutBuffer anc;
+        emitAnchorName(&anc, s, skipNonQualScopes(sc));
+        ident = Identifier::idPool(anc.peekString());
+    }
+    size_t *count = (size_t*)dmd_aaGet(&sc->anchorCounts, (void *)ident);
+    TemplateDeclaration *td = getEponymousParent(s);
+    // don't write an anchor for matching consecutive ditto symbols
+    if (*count > 0 && sc->prevAnchor == ident &&
+        sc->lastdc && (isDitto(s->comment) || (td && isDitto(td->comment))))
+        return;
+
+    (*count)++;
+    // cache anchor name
+    sc->prevAnchor = ident;
+
+    buf->writestring("$(DDOC_ANCHOR ");
+    buf->writestring(ident->toChars());
+    // only append count once there's a duplicate
+    if (*count != 1)
+        buf->printf(".%u", *count);
+    buf->writeByte(')');
+}
+
+/******************************* emitComment **********************************/
+
+/** Get leading indentation from 'src' which represents lines of code. */
+static size_t getCodeIndent(const char *src)
+{
+    while (src && (*src == '\r' || *src == '\n'))
+        ++src;  // skip until we find the first non-empty line
+
+    size_t codeIndent = 0;
+    while (src && (*src == ' ' || *src == '\t'))
+    {
+        codeIndent++;
+        src++;
+    }
+    return codeIndent;
+}
+
+/** Recursively expand template mixin member docs into the scope. */
+static void expandTemplateMixinComments(TemplateMixin *tm, OutBuffer *buf, Scope *sc)
+{
+    if (!tm->semanticRun) tm->semantic(sc);
+    TemplateDeclaration *td = (tm && tm->tempdecl) ?
+        tm->tempdecl->isTemplateDeclaration() : NULL;
+    if (td && td->members)
+    {
+        for (size_t i = 0; i < td->members->dim; i++)
+        {
+            Dsymbol *sm = (*td->members)[i];
+            TemplateMixin *tmc = sm->isTemplateMixin();
+            if (tmc && tmc->comment)
+                expandTemplateMixinComments(tmc, buf, sc);
+            else
+                emitComment(sm, buf, sc);
+        }
+    }
+}
+
+void emitMemberComments(ScopeDsymbol *sds, OutBuffer *buf, Scope *sc)
+{
+    if (!sds->members)
+        return;
+
+    //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars());
+
+    const char *m = "$(DDOC_MEMBERS ";
+    if (sds->isTemplateDeclaration())
+        m = "$(DDOC_TEMPLATE_MEMBERS ";
+    else if (sds->isClassDeclaration())
+        m = "$(DDOC_CLASS_MEMBERS ";
+    else if (sds->isStructDeclaration())
+        m = "$(DDOC_STRUCT_MEMBERS ";
+    else if (sds->isEnumDeclaration())
+        m = "$(DDOC_ENUM_MEMBERS ";
+    else if (sds->isModule())
+        m = "$(DDOC_MODULE_MEMBERS ";
+
+    size_t offset1 = buf->offset;         // save starting offset
+    buf->writestring(m);
+    size_t offset2 = buf->offset;         // to see if we write anything
+
+    sc = sc->push(sds);
+
+    for (size_t i = 0; i < sds->members->dim; i++)
+    {
+        Dsymbol *s = (*sds->members)[i];
+        //printf("\ts = '%s'\n", s->toChars());
+
+        // only expand if parent is a non-template (semantic won't work)
+        if (s->comment && s->isTemplateMixin() && s->parent && !s->parent->isTemplateDeclaration())
+            expandTemplateMixinComments((TemplateMixin *)s, buf, sc);
+
+        emitComment(s, buf, sc);
+    }
+    emitComment(NULL, buf, sc);
+
+    sc->pop();
+
+    if (buf->offset == offset2)
+    {
+        /* Didn't write out any members, so back out last write
+         */
+        buf->offset = offset1;
+    }
+    else
+        buf->writestring(")\n");
+}
+
+void emitProtection(OutBuffer *buf, Prot prot)
+{
+    if (prot.kind != PROTundefined && prot.kind != PROTpublic)
+    {
+        protectionToBuffer(buf, prot);
+        buf->writeByte(' ');
+    }
+}
+
+void emitComment(Dsymbol *s, OutBuffer *buf, Scope *sc)
+{
+    class EmitComment : public Visitor
+    {
+    public:
+        OutBuffer *buf;
+        Scope *sc;
+
+        EmitComment(OutBuffer *buf, Scope *sc)
+            : buf(buf), sc(sc)
+        {
+        }
+
+        void visit(Dsymbol *) {}
+        void visit(InvariantDeclaration *) {}
+        void visit(UnitTestDeclaration *) {}
+        void visit(PostBlitDeclaration *) {}
+        void visit(DtorDeclaration *) {}
+        void visit(StaticCtorDeclaration *) {}
+        void visit(StaticDtorDeclaration *) {}
+        void visit(TypeInfoDeclaration *) {}
+
+        void emit(Scope *sc, Dsymbol *s, const utf8_t *com)
+        {
+            if (s && sc->lastdc && isDitto(com))
+            {
+                sc->lastdc->a.push(s);
+                return;
+            }
+
+            // Put previous doc comment if exists
+            if (DocComment *dc = sc->lastdc)
+            {
+                // Put the declaration signatures as the document 'title'
+                buf->writestring(ddoc_decl_s);
+                for (size_t i = 0; i < dc->a.dim; i++)
+                {
+                    Dsymbol *sx = dc->a[i];
+
+                    if (i == 0)
+                    {
+                        size_t o = buf->offset;
+                        toDocBuffer(sx, buf, sc);
+                        highlightCode(sc, sx, buf, o);
+                        continue;
+                    }
+
+                    buf->writestring("$(DDOC_DITTO ");
+                    {
+                        size_t o = buf->offset;
+                        toDocBuffer(sx, buf, sc);
+                        highlightCode(sc, sx, buf, o);
+                    }
+                    buf->writeByte(')');
+                }
+                buf->writestring(ddoc_decl_e);
+
+                // Put the ddoc comment as the document 'description'
+                buf->writestring(ddoc_decl_dd_s);
+                {
+                    dc->writeSections(sc, &dc->a, buf);
+                    if (ScopeDsymbol *sds = dc->a[0]->isScopeDsymbol())
+                        emitMemberComments(sds, buf, sc);
+                }
+                buf->writestring(ddoc_decl_dd_e);
+                //printf("buf.2 = [[%.*s]]\n", buf->offset - o0, buf->data + o0);
+            }
+
+            if (s)
+            {
+                DocComment *dc = DocComment::parse(sc, s, com);
+                dc->pmacrotable = &sc->_module->macrotable;
+                sc->lastdc = dc;
+            }
+        }
+
+        void visit(Declaration *d)
+        {
+            //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", d, d->toChars(), d->comment);
+            //printf("type = %p\n", d->type);
+            const utf8_t *com = d->comment;
+            if (TemplateDeclaration *td = getEponymousParent(d))
+            {
+                if (isDitto(td->comment))
+                    com = td->comment;
+                else
+                    com = Lexer::combineComments(td->comment, com);
+            }
+            else
+            {
+                if (!d->ident)
+                    return;
+                if (!d->type && !d->isCtorDeclaration() && !d->isAliasDeclaration())
+                    return;
+                if (d->protection.kind == PROTprivate || sc->protection.kind == PROTprivate)
+                    return;
+            }
+            if (!com)
+                return;
+
+            emit(sc, d, com);
+        }
+
+        void visit(AggregateDeclaration *ad)
+        {
+            //printf("AggregateDeclaration::emitComment() '%s'\n", ad->toChars());
+            const utf8_t *com = ad->comment;
+            if (TemplateDeclaration *td = getEponymousParent(ad))
+            {
+                if (isDitto(td->comment))
+                    com = td->comment;
+                else
+                    com = Lexer::combineComments(td->comment, com);
+            }
+            else
+            {
+                if (ad->prot().kind == PROTprivate || sc->protection.kind == PROTprivate)
+                    return;
+                if (!ad->comment)
+                    return;
+            }
+            if (!com)
+                return;
+
+            emit(sc, ad, com);
+        }
+
+        void visit(TemplateDeclaration *td)
+        {
+            //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", td->toChars(), td->kind());
+            if (td->prot().kind == PROTprivate || sc->protection.kind == PROTprivate)
+                return;
+            if (!td->comment)
+                return;
+
+            if (Dsymbol *ss = getEponymousMember(td))
+            {
+                ss->accept(this);
+                return;
+            }
+            emit(sc, td, td->comment);
+        }
+
+        void visit(EnumDeclaration *ed)
+        {
+            if (ed->prot().kind == PROTprivate || sc->protection.kind == PROTprivate)
+                return;
+            if (ed->isAnonymous() && ed->members)
+            {
+                for (size_t i = 0; i < ed->members->dim; i++)
+                {
+                    Dsymbol *s = (*ed->members)[i];
+                    emitComment(s, buf, sc);
+                }
+                return;
+            }
+            if (!ed->comment)
+                return;
+            if (ed->isAnonymous())
+                return;
+
+            emit(sc, ed, ed->comment);
+        }
+
+        void visit(EnumMember *em)
+        {
+            //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", em, em->toChars(), em->comment);
+            if (em->prot().kind == PROTprivate || sc->protection.kind == PROTprivate)
+                return;
+            if (!em->comment)
+                return;
+
+            emit(sc, em, em->comment);
+        }
+
+        void visit(AttribDeclaration *ad)
+        {
+            //printf("AttribDeclaration::emitComment(sc = %p)\n", sc);
+
+            /* A general problem with this, illustrated by BUGZILLA 2516,
+             * is that attributes are not transmitted through to the underlying
+             * member declarations for template bodies, because semantic analysis
+             * is not done for template declaration bodies
+             * (only template instantiations).
+             * Hence, Ddoc omits attributes from template members.
+             */
+
+            Dsymbols *d = ad->include(NULL, NULL);
+
+            if (d)
+            {
+                for (size_t i = 0; i < d->dim; i++)
+                {
+                    Dsymbol *s = (*d)[i];
+                    //printf("AttribDeclaration::emitComment %s\n", s->toChars());
+                    emitComment(s, buf, sc);
+                }
+            }
+        }
+
+        void visit(ProtDeclaration *pd)
+        {
+            if (pd->decl)
+            {
+                Scope *scx = sc;
+                sc = sc->copy();
+                sc->protection = pd->protection;
+                visit((AttribDeclaration *)pd);
+                scx->lastdc = sc->lastdc;
+                sc = sc->pop();
+            }
+        }
+
+        void visit(ConditionalDeclaration *cd)
+        {
+            //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc);
+            if (cd->condition->inc)
+            {
+                visit((AttribDeclaration *)cd);
+                return;
+            }
+
+            /* If generating doc comment, be careful because if we're inside
+             * a template, then include(NULL, NULL) will fail.
+             */
+            Dsymbols *d = cd->decl ? cd->decl : cd->elsedecl;
+            for (size_t i = 0; i < d->dim; i++)
+            {
+                Dsymbol *s = (*d)[i];
+                emitComment(s, buf, sc);
+            }
+        }
+    };
+
+    EmitComment v(buf, sc);
+
+    if (!s)
+        v.emit(sc, NULL, NULL);
+    else
+        s->accept(&v);
+}
+
+/******************************* toDocBuffer **********************************/
+
+void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc)
+{
+    class ToDocBuffer : public Visitor
+    {
+    public:
+        OutBuffer *buf;
+        Scope *sc;
+
+        ToDocBuffer(OutBuffer *buf, Scope *sc)
+            : buf(buf), sc(sc)
+        {
+        }
+
+        void visit(Dsymbol *s)
+        {
+            //printf("Dsymbol::toDocbuffer() %s\n", s->toChars());
+            HdrGenState hgs;
+            hgs.ddoc = true;
+            ::toCBuffer(s, buf, &hgs);
+        }
+
+        void prefix(Dsymbol *s)
+        {
+            if (s->isDeprecated())
+                buf->writestring("deprecated ");
+
+            if (Declaration *d = s->isDeclaration())
+            {
+                emitProtection(buf, d->protection);
+
+                if (d->isStatic())
+                    buf->writestring("static ");
+                else if (d->isFinal())
+                    buf->writestring("final ");
+                else if (d->isAbstract())
+                    buf->writestring("abstract ");
+
+                if (!d->isFuncDeclaration())  // functionToBufferFull handles this
+                {
+                    if (d->isConst())
+                        buf->writestring("const ");
+                    if (d->isImmutable())
+                        buf->writestring("immutable ");
+                    if (d->isSynchronized())
+                        buf->writestring("synchronized ");
+
+                    if (d->storage_class & STCmanifest)
+                        buf->writestring("enum ");
+                }
+            }
+        }
+
+        void visit(Declaration *d)
+        {
+            if (!d->ident)
+                return;
+
+            TemplateDeclaration *td = getEponymousParent(d);
+            //printf("Declaration::toDocbuffer() %s, originalType = %s, td = %s\n", d->toChars(), d->originalType ? d->originalType->toChars() : "--", td ? td->toChars() : "--");
+
+            HdrGenState hgs;
+            hgs.ddoc = true;
+
+            if (d->isDeprecated())
+                buf->writestring("$(DEPRECATED ");
+
+            prefix(d);
+
+            if (d->type)
+            {
+                Type *origType = d->originalType ? d->originalType : d->type;
+                if (origType->ty == Tfunction)
+                {
+                    functionToBufferFull((TypeFunction *)origType, buf, d->ident, &hgs, td);
+                }
+                else
+                    ::toCBuffer(origType, buf, d->ident, &hgs);
+            }
+            else
+                buf->writestring(d->ident->toChars());
+
+            if (d->isVarDeclaration() && td)
+            {
+                buf->writeByte('(');
+                if (td->origParameters && td->origParameters->dim)
+                {
+                    for (size_t i = 0; i < td->origParameters->dim; i++)
+                    {
+                        if (i)
+                            buf->writestring(", ");
+                        toCBuffer((*td->origParameters)[i], buf, &hgs);
+                    }
+                }
+                buf->writeByte(')');
+            }
+
+            // emit constraints if declaration is a templated declaration
+            if (td && td->constraint)
+            {
+                buf->writestring(" if (");
+                ::toCBuffer(td->constraint, buf, &hgs);
+                buf->writeByte(')');
+            }
+
+            if (d->isDeprecated())
+                buf->writestring(")");
+
+            buf->writestring(";\n");
+        }
+
+        void visit(AliasDeclaration *ad)
+        {
+            //printf("AliasDeclaration::toDocbuffer() %s\n", ad->toChars());
+            if (!ad->ident)
+                return;
+
+            if (ad->isDeprecated())
+                buf->writestring("deprecated ");
+
+            emitProtection(buf, ad->protection);
+            buf->printf("alias %s = ", ad->toChars());
+
+            if (Dsymbol *s = ad->aliassym)  // ident alias
+            {
+                prettyPrintDsymbol(s, ad->parent);
+            }
+            else if (Type *type = ad->getType())  // type alias
+            {
+                if (type->ty == Tclass || type->ty == Tstruct || type->ty == Tenum)
+                {
+                    if (Dsymbol *s = type->toDsymbol(NULL))  // elaborate type
+                        prettyPrintDsymbol(s, ad->parent);
+                    else
+                        buf->writestring(type->toChars());
+                }
+                else
+                {
+                    // simple type
+                    buf->writestring(type->toChars());
+                }
+            }
+
+            buf->writestring(";\n");
+        }
+
+        void parentToBuffer(Dsymbol *s)
+        {
+            if (s && !s->isPackage() && !s->isModule())
+            {
+                parentToBuffer(s->parent);
+                buf->writestring(s->toChars());
+                buf->writestring(".");
+            }
+        }
+
+        static bool inSameModule(Dsymbol *s, Dsymbol *p)
+        {
+            for ( ; s ; s = s->parent)
+            {
+                if (s->isModule())
+                    break;
+            }
+
+            for ( ; p ; p = p->parent)
+            {
+                if (p->isModule())
+                    break;
+            }
+
+            return s == p;
+        }
+
+        void prettyPrintDsymbol(Dsymbol *s, Dsymbol *parent)
+        {
+            if (s->parent && (s->parent == parent))  // in current scope -> naked name
+            {
+                buf->writestring(s->toChars());
+            }
+            else if (!inSameModule(s, parent))  // in another module -> full name
+            {
+                buf->writestring(s->toPrettyChars());
+            }
+            else  // nested in a type in this module -> full name w/o module name
+            {
+                // if alias is nested in a user-type use module-scope lookup
+                if (!parent->isModule() && !parent->isPackage())
+                    buf->writestring(".");
+
+                parentToBuffer(s->parent);
+                buf->writestring(s->toChars());
+            }
+        }
+
+        void visit(AggregateDeclaration *ad)
+        {
+            if (!ad->ident)
+                return;
+
+        #if 0
+            emitProtection(buf, ad->protection);
+        #endif
+            buf->printf("%s %s", ad->kind(), ad->toChars());
+            buf->writestring(";\n");
+        }
+
+        void visit(StructDeclaration *sd)
+        {
+            //printf("StructDeclaration::toDocbuffer() %s\n", sd->toChars());
+            if (!sd->ident)
+                return;
+
+        #if 0
+            emitProtection(buf, sd->protection);
+        #endif
+            if (TemplateDeclaration *td = getEponymousParent(sd))
+            {
+                toDocBuffer(td, buf, sc);
+            }
+            else
+            {
+                buf->printf("%s %s", sd->kind(), sd->toChars());
+            }
+            buf->writestring(";\n");
+        }
+
+        void visit(ClassDeclaration *cd)
+        {
+            //printf("ClassDeclaration::toDocbuffer() %s\n", cd->toChars());
+            if (!cd->ident)
+                return;
+
+        #if 0
+            emitProtection(buf, cd->protection);
+        #endif
+            if (TemplateDeclaration *td = getEponymousParent(cd))
+            {
+                toDocBuffer(td, buf, sc);
+            }
+            else
+            {
+                if (!cd->isInterfaceDeclaration() && cd->isAbstract())
+                    buf->writestring("abstract ");
+                buf->printf("%s %s", cd->kind(), cd->toChars());
+            }
+            int any = 0;
+            for (size_t i = 0; i < cd->baseclasses->dim; i++)
+            {
+                BaseClass *bc = (*cd->baseclasses)[i];
+
+                if (bc->sym && bc->sym->ident == Id::Object)
+                    continue;
+
+                if (any)
+                    buf->writestring(", ");
+                else
+                {
+                    buf->writestring(": ");
+                    any = 1;
+                }
+                emitProtection(buf, Prot(PROTpublic));
+                if (bc->sym)
+                {
+                    buf->printf("$(DDOC_PSUPER_SYMBOL %s)", bc->sym->toPrettyChars());
+                }
+                else
+                {
+                    HdrGenState hgs;
+                    ::toCBuffer(bc->type, buf, NULL, &hgs);
+                }
+            }
+            buf->writestring(";\n");
+        }
+
+        void visit(EnumDeclaration *ed)
+        {
+            if (!ed->ident)
+                return;
+
+            buf->printf("%s %s", ed->kind(), ed->toChars());
+            if (ed->memtype)
+            {
+                buf->writestring(": $(DDOC_ENUM_BASETYPE ");
+                HdrGenState hgs;
+                ::toCBuffer(ed->memtype, buf, NULL, &hgs);
+                buf->writestring(")");
+            }
+            buf->writestring(";\n");
+        }
+
+        void visit(EnumMember *em)
+        {
+            if (!em->ident)
+                return;
+
+            buf->writestring(em->toChars());
+        }
+    };
+
+    ToDocBuffer v(buf, sc);
+    s->accept(&v);
+}
+
+/********************************* DocComment *********************************/
+
+DocComment *DocComment::parse(Scope *sc, Dsymbol *s, const utf8_t *comment)
+{
+    //printf("parse(%s): '%s'\n", s->toChars(), comment);
+    DocComment *dc = new DocComment();
+    dc->a.push(s);
+    if (!comment)
+        return dc;
+
+    dc->parseSections(comment);
+
+    for (size_t i = 0; i < dc->sections.dim; i++)
+    {
+        Section *sec = dc->sections[i];
+
+        if (icmp("copyright", sec->name, sec->namelen) == 0)
+        {
+            dc->copyright = sec;
+        }
+        if (icmp("macros", sec->name, sec->namelen) == 0)
+        {
+            dc->macros = sec;
+        }
+    }
+
+    return dc;
+}
+
+/*****************************************
+ * Parse next paragraph out of *pcomment.
+ * Update *pcomment to point past paragraph.
+ * Returns NULL if no more paragraphs.
+ * If paragraph ends in 'identifier:',
+ * then (*pcomment)[0 .. idlen] is the identifier.
+ */
+
+void DocComment::parseSections(const utf8_t *comment)
+{
+    const utf8_t *p;
+    const utf8_t *pstart;
+    const utf8_t *pend;
+    const utf8_t *idstart = NULL;       // dead-store to prevent spurious warning
+    size_t idlen;
+
+    const utf8_t *name = NULL;
+    size_t namelen = 0;
+
+    //printf("parseSections('%s')\n", comment);
+    p = comment;
+    while (*p)
+    {
+        const utf8_t *pstart0 = p;
+        p = skipwhitespace(p);
+        pstart = p;
+        pend = p;
+
+        /* Find end of section, which is ended by one of:
+         *      'identifier:' (but not inside a code section)
+         *      '\0'
+         */
+        idlen = 0;
+        int inCode = 0;
+        while (1)
+        {
+            // Check for start/end of a code section
+            if (*p == '-')
+            {
+                if (!inCode)
+                {
+                    // restore leading indentation
+                    while (pstart0 < pstart && isIndentWS(pstart-1)) --pstart;
+                }
+
+                int numdash = 0;
+                while (*p == '-')
+                {
+                    ++numdash;
+                    p++;
+                }
+                // BUG: handle UTF PS and LS too
+                if ((!*p || *p == '\r' || *p == '\n') && numdash >= 3)
+                    inCode ^= 1;
+                pend = p;
+            }
+
+            if (!inCode && isIdStart(p))
+            {
+                const utf8_t *q = p + utfStride(p);
+                while (isIdTail(q))
+                    q += utfStride(q);
+                if (*q == ':')  // identifier: ends it
+                {
+                    idlen = q - p;
+                    idstart = p;
+                    for (pend = p; pend > pstart; pend--)
+                    {
+                        if (pend[-1] == '\n')
+                            break;
+                    }
+                    p = q + 1;
+                    break;
+                }
+            }
+            while (1)
+            {
+                if (!*p)
+                    goto L1;
+                if (*p == '\n')
+                {
+                    p++;
+                    if (*p == '\n' && !summary && !namelen && !inCode)
+                    {
+                        pend = p;
+                        p++;
+                        goto L1;
+                    }
+                    break;
+                }
+                p++;
+                pend = p;
+            }
+            p = skipwhitespace(p);
+        }
+      L1:
+
+        if (namelen || pstart < pend)
+        {
+            Section *s;
+            if (icmp("Params", name, namelen) == 0)
+                s = new ParamSection();
+            else if (icmp("Macros", name, namelen) == 0)
+                s = new MacroSection();
+            else
+                s = new Section();
+            s->name = name;
+            s->namelen = namelen;
+            s->body = pstart;
+            s->bodylen = pend - pstart;
+            s->nooutput = 0;
+
+            //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body);
+
+            sections.push(s);
+
+            if (!summary && !namelen)
+                summary = s;
+        }
+
+        if (idlen)
+        {
+            name = idstart;
+            namelen = idlen;
+        }
+        else
+        {
+            name = NULL;
+            namelen = 0;
+            if (!*p)
+                break;
+        }
+    }
+}
+
+void DocComment::writeSections(Scope *sc, Dsymbols *a, OutBuffer *buf)
+{
+    assert(a->dim);
+
+    //printf("DocComment::writeSections()\n");
+    Loc loc = (*a)[0]->loc;
+    if (Module *m = (*a)[0]->isModule())
+    {
+        if (m->md)
+            loc = m->md->loc;
+    }
+
+    size_t offset1 = buf->offset;
+    buf->writestring("$(DDOC_SECTIONS ");
+    size_t offset2 = buf->offset;
+
+    for (size_t i = 0; i < sections.dim; i++)
+    {
+        Section *sec = sections[i];
+        if (sec->nooutput)
+            continue;
+
+        //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body);
+        if (!sec->namelen && i == 0)
+        {
+            buf->writestring("$(DDOC_SUMMARY ");
+            size_t o = buf->offset;
+            buf->write(sec->body, sec->bodylen);
+            escapeStrayParenthesis(loc, buf, o);
+            highlightText(sc, a, buf, o);
+            buf->writestring(")\n");
+        }
+        else
+            sec->write(loc, this, sc, a, buf);
+    }
+
+    for (size_t i = 0; i < a->dim; i++)
+    {
+        Dsymbol *s = (*a)[i];
+        if (Dsymbol *td = getEponymousParent(s))
+            s = td;
+
+        for (UnitTestDeclaration *utd = s->ddocUnittest; utd; utd = utd->ddocUnittest)
+        {
+            if (utd->protection.kind == PROTprivate || !utd->comment || !utd->fbody)
+                continue;
+
+            // Strip whitespaces to avoid showing empty summary
+            const utf8_t *c = utd->comment;
+            while (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r') ++c;
+
+            buf->writestring("$(DDOC_EXAMPLES ");
+
+            size_t o = buf->offset;
+            buf->writestring((char *)c);
+
+            if (utd->codedoc)
+            {
+                size_t n = getCodeIndent(utd->codedoc);
+                while (n--) buf->writeByte(' ');
+                buf->writestring("----\n");
+                buf->writestring(utd->codedoc);
+                buf->writestring("----\n");
+                highlightText(sc, a, buf, o);
+            }
+
+            buf->writestring(")");
+        }
+    }
+
+    if (buf->offset == offset2)
+    {
+        /* Didn't write out any sections, so back out last write
+         */
+        buf->offset = offset1;
+        buf->writestring("$(DDOC_BLANKLINE)\n");
+    }
+    else
+        buf->writestring(")\n");
+}
+
+/***************************************************
+ */
+
+void Section::write(Loc loc, DocComment *dc, Scope *sc, Dsymbols *a, OutBuffer *buf)
+{
+    assert(a->dim);
+
+    if (namelen)
+    {
+        static const char *table[] =
+        {
+            "AUTHORS", "BUGS", "COPYRIGHT", "DATE",
+            "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE",
+            "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS",
+            "VERSION", NULL
+        };
+
+        for (size_t i = 0; table[i]; i++)
+        {
+            if (icmp(table[i], name, namelen) == 0)
+            {
+                buf->printf("$(DDOC_%s ", table[i]);
+                goto L1;
+            }
+        }
+
+        buf->writestring("$(DDOC_SECTION ");
+
+            // Replace _ characters with spaces
+            buf->writestring("$(DDOC_SECTION_H ");
+            size_t o = buf->offset;
+            for (size_t u = 0; u < namelen; u++)
+            {
+                utf8_t c = name[u];
+                buf->writeByte((c == '_') ? ' ' : c);
+            }
+            escapeStrayParenthesis(loc, buf, o);
+            buf->writestring(":)\n");
+    }
+    else
+    {
+        buf->writestring("$(DDOC_DESCRIPTION ");
+    }
+  L1:
+    size_t o = buf->offset;
+    buf->write(body, bodylen);
+    escapeStrayParenthesis(loc, buf, o);
+    highlightText(sc, a, buf, o);
+    buf->writestring(")\n");
+}
+
+/***************************************************
+ */
+
+void ParamSection::write(Loc loc, DocComment *dc, Scope *sc, Dsymbols *a, OutBuffer *buf)
+{
+    assert(a->dim);
+    Dsymbol *s = (*a)[0];   // test
+
+    const utf8_t *p = body;
+    size_t len = bodylen;
+    const utf8_t *pend = p + len;
+
+    const utf8_t *tempstart = NULL;
+    size_t templen = 0;
+
+    const utf8_t *namestart = NULL;
+    size_t namelen = 0;       // !=0 if line continuation
+
+    const utf8_t *textstart = NULL;
+    size_t textlen = 0;
+
+    size_t paramcount = 0;
+
+    buf->writestring("$(DDOC_PARAMS ");
+    while (p < pend)
+    {
+        // Skip to start of macro
+        while (1)
+        {
+            switch (*p)
+            {
+                case ' ':
+                case '\t':
+                    p++;
+                    continue;
+
+                case '\n':
+                    p++;
+                    goto Lcont;
+
+                default:
+                    if (isIdStart(p) || isCVariadicArg(p, pend - p))
+                        break;
+                    if (namelen)
+                        goto Ltext;             // continuation of prev macro
+                    goto Lskipline;
+            }
+            break;
+        }
+        tempstart = p;
+
+        while (isIdTail(p))
+            p += utfStride(p);
+        if (isCVariadicArg(p, pend - p))
+            p += 3;
+
+        templen = p - tempstart;
+
+        while (*p == ' ' || *p == '\t')
+            p++;
+
+        if (*p != '=')
+        {
+            if (namelen)
+                goto Ltext;             // continuation of prev macro
+            goto Lskipline;
+        }
+        p++;
+
+        if (namelen)
+        {
+            // Output existing param
+
+        L1:
+            //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart);
+            ++paramcount;
+            HdrGenState hgs;
+            buf->writestring("$(DDOC_PARAM_ROW ");
+            {
+                buf->writestring("$(DDOC_PARAM_ID ");
+                {
+                    size_t o = buf->offset;
+                    Parameter *fparam = isFunctionParameter(a, namestart, namelen);
+                    bool isCVariadic = isCVariadicParameter(a, namestart, namelen);
+                    if (isCVariadic)
+                    {
+                        buf->writestring("...");
+                    }
+                    else if (fparam && fparam->type && fparam->ident)
+                    {
+                        ::toCBuffer(fparam->type, buf, fparam->ident, &hgs);
+                    }
+                    else
+                    {
+                        if (isTemplateParameter(a, namestart, namelen))
+                        {
+                            // 10236: Don't count template parameters for params check
+                            --paramcount;
+                        }
+                        else if (!fparam)
+                        {
+                            warning(s->loc, "Ddoc: function declaration has no parameter '%.*s'", namelen, namestart);
+                        }
+                        buf->write(namestart, namelen);
+                    }
+                    escapeStrayParenthesis(loc, buf, o);
+                    highlightCode(sc, a, buf, o);
+                }
+                buf->writestring(")\n");
+
+                buf->writestring("$(DDOC_PARAM_DESC ");
+                {
+                    size_t o = buf->offset;
+                    buf->write(textstart, textlen);
+                    escapeStrayParenthesis(loc, buf, o);
+                    highlightText(sc, a, buf, o);
+                }
+                buf->writestring(")");
+            }
+            buf->writestring(")\n");
+            namelen = 0;
+            if (p >= pend)
+                break;
+        }
+
+        namestart = tempstart;
+        namelen = templen;
+
+        while (*p == ' ' || *p == '\t')
+            p++;
+        textstart = p;
+
+      Ltext:
+        while (*p != '\n')
+            p++;
+        textlen = p - textstart;
+        p++;
+
+     Lcont:
+        continue;
+
+     Lskipline:
+        // Ignore this line
+        while (*p++ != '\n')
+            ;
+    }
+    if (namelen)
+        goto L1;                // write out last one
+    buf->writestring(")\n");
+
+    TypeFunction *tf = a->dim == 1 ? isTypeFunction(s) : NULL;
+    if (tf)
+    {
+        size_t pcount = (tf->parameters ? tf->parameters->dim : 0) + (int)(tf->varargs == 1);
+        if (pcount != paramcount)
+        {
+            warning(s->loc, "Ddoc: parameter count mismatch");
+        }
+    }
+}
+
+/***************************************************
+ */
+
+void MacroSection::write(Loc loc, DocComment *dc, Scope *sc, Dsymbols *a, OutBuffer *buf)
+{
+    //printf("MacroSection::write()\n");
+    DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen);
+}
+
+/************************************************
+ * Parse macros out of Macros: section.
+ * Macros are of the form:
+ *      name1 = value1
+ *
+ *      name2 = value2
+ */
+
+void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, const utf8_t *m, size_t mlen)
+{
+    const utf8_t *p = m;
+    size_t len = mlen;
+    const utf8_t *pend = p + len;
+
+    const utf8_t *tempstart = NULL;
+    size_t templen = 0;
+
+    const utf8_t *namestart = NULL;
+    size_t namelen = 0;       // !=0 if line continuation
+
+    const utf8_t *textstart = NULL;
+    size_t textlen = 0;
+
+    while (p < pend)
+    {
+        // Skip to start of macro
+        while (1)
+        {
+            if (p >= pend)
+                goto Ldone;
+            switch (*p)
+            {
+                case ' ':
+                case '\t':
+                    p++;
+                    continue;
+
+                case '\r':
+                case '\n':
+                    p++;
+                    goto Lcont;
+
+                default:
+                    if (isIdStart(p))
+                        break;
+                    if (namelen)
+                        goto Ltext;             // continuation of prev macro
+                    goto Lskipline;
+            }
+            break;
+        }
+        tempstart = p;
+
+        while (1)
+        {
+            if (p >= pend)
+                goto Ldone;
+            if (!isIdTail(p))
+                break;
+            p += utfStride(p);
+        }
+        templen = p - tempstart;
+
+        while (1)
+        {
+            if (p >= pend)
+                goto Ldone;
+            if (!(*p == ' ' || *p == '\t'))
+                break;
+            p++;
+        }
+
+        if (*p != '=')
+        {
+            if (namelen)
+                goto Ltext;             // continuation of prev macro
+            goto Lskipline;
+        }
+        p++;
+        if (p >= pend)
+            goto Ldone;
+
+        if (namelen)
+        {
+            // Output existing macro
+        L1:
+            //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart);
+            if (icmp("ESCAPES", namestart, namelen) == 0)
+                parseEscapes(pescapetable, textstart, textlen);
+            else
+                Macro::define(pmacrotable, namestart, namelen, textstart, textlen);
+            namelen = 0;
+            if (p >= pend)
+                break;
+        }
+
+        namestart = tempstart;
+        namelen = templen;
+
+        while (p < pend && (*p == ' ' || *p == '\t'))
+            p++;
+        textstart = p;
+
+      Ltext:
+        while (p < pend && *p != '\r' && *p != '\n')
+            p++;
+        textlen = p - textstart;
+
+        p++;
+        //printf("p = %p, pend = %p\n", p, pend);
+
+     Lcont:
+        continue;
+
+     Lskipline:
+        // Ignore this line
+        while (p < pend && *p != '\r' && *p != '\n')
+            p++;
+    }
+Ldone:
+    if (namelen)
+        goto L1;                // write out last one
+}
+
+/**************************************
+ * Parse escapes of the form:
+ *      /c/string/
+ * where c is a single character.
+ * Multiple escapes can be separated
+ * by whitespace and/or commas.
+ */
+
+void DocComment::parseEscapes(Escape **pescapetable, const utf8_t *textstart, size_t textlen)
+{
+    Escape *escapetable = *pescapetable;
+
+    if (!escapetable)
+    {
+        escapetable = new Escape;
+        memset(escapetable, 0, sizeof(Escape));
+        *pescapetable = escapetable;
+    }
+    //printf("parseEscapes('%.*s') pescapetable = %p\n", textlen, textstart, pescapetable);
+    const utf8_t *p = textstart;
+    const utf8_t *pend = p + textlen;
+
+    while (1)
+    {
+        while (1)
+        {
+            if (p + 4 >= pend)
+                return;
+            if (!(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == ','))
+                break;
+            p++;
+        }
+        if (p[0] != '/' || p[2] != '/')
+            return;
+        utf8_t c = p[1];
+        p += 3;
+        const utf8_t *start = p;
+        while (1)
+        {
+            if (p >= pend)
+                return;
+            if (*p == '/')
+                break;
+            p++;
+        }
+        size_t len = p - start;
+        char *s = (char *)memcpy(mem.xmalloc(len + 1), start, len);
+        s[len] = 0;
+        escapetable->strings[c] = s;
+        //printf("\t%c = '%s'\n", c, s);
+        p++;
+    }
+}
+
+
+/******************************************
+ * Compare 0-terminated string with length terminated string.
+ * Return < 0, ==0, > 0
+ */
+
+int cmp(const char *stringz, const void *s, size_t slen)
+{
+    size_t len1 = strlen(stringz);
+
+    if (len1 != slen)
+        return (int)(len1 - slen);
+    return memcmp(stringz, s, slen);
+}
+
+int icmp(const char *stringz, const void *s, size_t slen)
+{
+    size_t len1 = strlen(stringz);
+
+    if (len1 != slen)
+        return (int)(len1 - slen);
+    return Port::memicmp(stringz, (char *)s, slen);
+}
+
+/*****************************************
+ * Return true if comment consists entirely of "ditto".
+ */
+
+bool isDitto(const utf8_t *comment)
+{
+    if (comment)
+    {
+        const utf8_t *p = skipwhitespace(comment);
+
+        if (Port::memicmp((const char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0)
+            return true;
+    }
+    return false;
+}
+
+/**********************************************
+ * Skip white space.
+ */
+
+const utf8_t *skipwhitespace(const utf8_t *p)
+{
+    for (; 1; p++)
+    {
+        switch (*p)
+        {
+            case ' ':
+            case '\t':
+            case '\n':
+                continue;
+        }
+        break;
+    }
+    return p;
+}
+
+
+/************************************************
+ * Scan forward to one of:
+ *      start of identifier
+ *      beginning of next line
+ *      end of buf
+ */
+
+size_t skiptoident(OutBuffer *buf, size_t i)
+{
+    while (i < buf->offset)
+    {
+        dchar_t c;
+
+        size_t oi = i;
+        if (utf_decodeChar((utf8_t *)buf->data, buf->offset, &i, &c))
+        {
+            /* Ignore UTF errors, but still consume input
+             */
+            break;
+        }
+        if (c >= 0x80)
+        {
+            if (!isUniAlpha(c))
+                continue;
+        }
+        else if (!(isalpha(c) || c == '_' || c == '\n'))
+            continue;
+        i = oi;
+        break;
+    }
+    return i;
+}
+
+/************************************************
+ * Scan forward past end of identifier.
+ */
+
+size_t skippastident(OutBuffer *buf, size_t i)
+{
+    while (i < buf->offset)
+    {
+        dchar_t c;
+
+        size_t oi = i;
+        if (utf_decodeChar((utf8_t *)buf->data, buf->offset, &i, &c))
+        {
+            /* Ignore UTF errors, but still consume input
+             */
+            break;
+        }
+        if (c >= 0x80)
+        {
+            if (isUniAlpha(c))
+                continue;
+        }
+        else if (isalnum(c) || c == '_')
+            continue;
+        i = oi;
+        break;
+    }
+    return i;
+}
+
+
+/************************************************
+ * Scan forward past URL starting at i.
+ * We don't want to highlight parts of a URL.
+ * Returns:
+ *      i if not a URL
+ *      index just past it if it is a URL
+ */
+
+size_t skippastURL(OutBuffer *buf, size_t i)
+{
+    size_t length = buf->offset - i;
+    utf8_t *p = (utf8_t *)&buf->data[i];
+    size_t j;
+    unsigned sawdot = 0;
+
+    if (length > 7 && Port::memicmp((char *)p, "http://", 7) == 0)
+    {
+        j = 7;
+    }
+    else if (length > 8 && Port::memicmp((char *)p, "https://", 8) == 0)
+    {
+        j = 8;
+    }
+    else
+        goto Lno;
+
+    for (; j < length; j++)
+    {
+        utf8_t c = p[j];
+        if (isalnum(c))
+            continue;
+        if (c == '-' || c == '_' || c == '?' ||
+            c == '=' || c == '%' || c == '&' ||
+            c == '/' || c == '+' || c == '#' ||
+            c == '~')
+            continue;
+        if (c == '.')
+        {
+            sawdot = 1;
+            continue;
+        }
+        break;
+    }
+    if (sawdot)
+        return i + j;
+
+Lno:
+    return i;
+}
+
+
+/****************************************************
+ */
+
+bool isIdentifier(Dsymbols *a, const utf8_t *p, size_t len)
+{
+    for (size_t i = 0; i < a->dim; i++)
+    {
+        const char *s = (*a)[i]->ident->toChars();
+        if (cmp(s, p, len) == 0)
+            return true;
+    }
+    return false;
+}
+
+/****************************************************
+ */
+
+bool isKeyword(utf8_t *p, size_t len)
+{
+    static const char *table[] = { "true", "false", "null", NULL };
+
+    for (int i = 0; table[i]; i++)
+    {
+        if (cmp(table[i], p, len) == 0)
+            return true;
+    }
+    return false;
+}
+
+/****************************************************
+ */
+
+TypeFunction *isTypeFunction(Dsymbol *s)
+{
+    FuncDeclaration *f = s->isFuncDeclaration();
+
+    /* f->type may be NULL for template members.
+     */
+    if (f && f->type)
+    {
+        Type *t = f->originalType ? f->originalType : f->type;
+        if (t->ty == Tfunction)
+            return (TypeFunction *)t;
+    }
+    return NULL;
+}
+
+/****************************************************
+ */
+
+Parameter *isFunctionParameter(Dsymbols *a, const utf8_t *p, size_t len)
+{
+    for (size_t i = 0; i < a->dim; i++)
+    {
+        TypeFunction *tf = isTypeFunction((*a)[i]);
+        if (tf && tf->parameters)
+        {
+            for (size_t k = 0; k < tf->parameters->dim; k++)
+            {
+                Parameter *fparam = (*tf->parameters)[k];
+                if (fparam->ident && cmp(fparam->ident->toChars(), p, len) == 0)
+                {
+                    return fparam;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+/****************************************************
+ */
+
+TemplateParameter *isTemplateParameter(Dsymbols *a, const utf8_t *p, size_t len)
+{
+    for (size_t i = 0; i < a->dim; i++)
+    {
+        TemplateDeclaration *td = getEponymousParent((*a)[i]);
+        if (td && td->origParameters)
+        {
+            for (size_t k = 0; k < td->origParameters->dim; k++)
+            {
+                TemplateParameter *tp = (*td->origParameters)[k];
+                if (tp->ident && cmp(tp->ident->toChars(), p, len) == 0)
+                {
+                    return tp;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+/****************************************************
+ * Return true if str is a reserved symbol name
+ * that starts with a double underscore.
+ */
+
+bool isReservedName(utf8_t *str, size_t len)
+{
+    static const char *table[] = {
+        "__ctor", "__dtor", "__postblit", "__invariant", "__unitTest",
+        "__require", "__ensure", "__dollar", "__ctfe", "__withSym", "__result",
+        "__returnLabel", "__vptr", "__monitor", "__gate", "__xopEquals", "__xopCmp",
+        "__LINE__", "__FILE__", "__MODULE__", "__FUNCTION__", "__PRETTY_FUNCTION__",
+        "__DATE__", "__TIME__", "__TIMESTAMP__", "__VENDOR__", "__VERSION__",
+        "__EOF__", "__LOCAL_SIZE", "___tls_get_addr", "__entrypoint", NULL };
+
+    for (int i = 0; table[i]; i++)
+    {
+        if (cmp(table[i], str, len) == 0)
+            return true;
+    }
+    return false;
+}
+
+/**************************************************
+ * Highlight text section.
+ */
+
+void highlightText(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset)
+{
+    Dsymbol *s = a->dim ? (*a)[0] : NULL;   // test
+
+    //printf("highlightText()\n");
+
+    int leadingBlank = 1;
+    int inCode = 0;
+    int inBacktick = 0;
+    //int inComment = 0;                  // in <!-- ... --> comment
+    size_t iCodeStart = 0;                    // start of code section
+    size_t codeIndent = 0;
+
+    size_t iLineStart = offset;
+
+    for (size_t i = offset; i < buf->offset; i++)
+    {
+        utf8_t c = buf->data[i];
+
+     Lcont:
+        switch (c)
+        {
+            case ' ':
+            case '\t':
+                break;
+
+            case '\n':
+                if (inBacktick)
+                {
+                    // `inline code` is only valid if contained on a single line
+                    // otherwise, the backticks should be output literally.
+                    //
+                    // This lets things like `output from the linker' display
+                    // unmolested while keeping the feature consistent with GitHub.
+
+                    inBacktick = false;
+                    inCode = false; // the backtick also assumes we're in code
+
+                    // Nothing else is necessary since the DDOC_BACKQUOTED macro is
+                    // inserted lazily at the close quote, meaning the rest of the
+                    // text is already OK.
+                }
+
+                if (!sc->_module->isDocFile &&
+                    !inCode && i == iLineStart && i + 1 < buf->offset)    // if "\n\n"
+                {
+                    static const char blankline[] = "$(DDOC_BLANKLINE)\n";
+
+                    i = buf->insert(i, blankline, strlen(blankline));
+                }
+                leadingBlank = 1;
+                iLineStart = i + 1;
+                break;
+
+            case '<':
+            {
+                leadingBlank = 0;
+                if (inCode)
+                    break;
+                utf8_t *p = (utf8_t *)&buf->data[i];
+                const char *se = sc->_module->escapetable->escapeChar('<');
+                if (se && strcmp(se, "&lt;") == 0)
+                {
+                    // Generating HTML
+                    // Skip over comments
+                    if (p[1] == '!' && p[2] == '-' && p[3] == '-')
+                    {
+                        size_t j = i + 4;
+                        p += 4;
+                        while (1)
+                        {
+                            if (j == buf->offset)
+                                goto L1;
+                            if (p[0] == '-' && p[1] == '-' && p[2] == '>')
+                            {
+                                i = j + 2;  // place on closing '>'
+                                break;
+                            }
+                            j++;
+                            p++;
+                        }
+                        break;
+                    }
+
+                    // Skip over HTML tag
+                    if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2])))
+                    {
+                        size_t j = i + 2;
+                        p += 2;
+                        while (1)
+                        {
+                            if (j == buf->offset)
+                                break;
+                            if (p[0] == '>')
+                            {
+                                i = j;      // place on closing '>'
+                                break;
+                            }
+                            j++;
+                            p++;
+                        }
+                        break;
+                    }
+                }
+            L1:
+                // Replace '<' with '&lt;' character entity
+                if (se)
+                {
+                    size_t len = strlen(se);
+                    buf->remove(i, 1);
+                    i = buf->insert(i, se, len);
+                    i--;        // point to ';'
+                }
+                break;
+            }
+            case '>':
+            {
+                leadingBlank = 0;
+                if (inCode)
+                    break;
+                // Replace '>' with '&gt;' character entity
+                const char *se = sc->_module->escapetable->escapeChar('>');
+                if (se)
+                {
+                    size_t len = strlen(se);
+                    buf->remove(i, 1);
+                    i = buf->insert(i, se, len);
+                    i--;        // point to ';'
+                }
+                break;
+            }
+            case '&':
+            {
+                leadingBlank = 0;
+                if (inCode)
+                    break;
+                utf8_t *p = (utf8_t *)&buf->data[i];
+                if (p[1] == '#' || isalpha(p[1]))
+                    break;                      // already a character entity
+                // Replace '&' with '&amp;' character entity
+                const char *se = sc->_module->escapetable->escapeChar('&');
+                if (se)
+                {
+                    size_t len = strlen(se);
+                    buf->remove(i, 1);
+                    i = buf->insert(i, se, len);
+                    i--;        // point to ';'
+                }
+                break;
+            }
+            case '`':
+            {
+                if (inBacktick)
+                {
+                    inBacktick = 0;
+                    inCode = 0;
+
+                    OutBuffer codebuf;
+
+                    codebuf.write(buf->data + iCodeStart + 1, i - (iCodeStart + 1));
+
+                    // escape the contents, but do not perform highlighting except for DDOC_PSYMBOL
+                    highlightCode(sc, a, &codebuf, 0);
+
+                    buf->remove(iCodeStart, i - iCodeStart + 1); // also trimming off the current `
+
+                    static const char pre[] = "$(DDOC_BACKQUOTED ";
+                    i = buf->insert(iCodeStart, pre, strlen(pre));
+                    i = buf->insert(i, (char *)codebuf.data, codebuf.offset);
+                    i = buf->insert(i, (char *)")", 1);
+
+                    i--; // point to the ending ) so when the for loop does i++, it will see the next character
+
+                    break;
+                }
+
+                if (inCode)
+                    break;
+
+                inCode = 1;
+                inBacktick = 1;
+                codeIndent = 0; // inline code is not indented
+
+                // All we do here is set the code flags and record
+                // the location. The macro will be inserted lazily
+                // so we can easily cancel the inBacktick if we come
+                // across a newline character.
+                iCodeStart = i;
+
+                break;
+            }
+            case '-':
+                /* A line beginning with --- delimits a code section.
+                 * inCode tells us if it is start or end of a code section.
+                 */
+                if (leadingBlank)
+                {
+                    size_t istart = i;
+                    size_t eollen = 0;
+
+                    leadingBlank = 0;
+                    while (1)
+                    {
+                        ++i;
+                        if (i >= buf->offset)
+                            break;
+                        c = buf->data[i];
+                        if (c == '\n')
+                        {
+                            eollen = 1;
+                            break;
+                        }
+                        if (c == '\r')
+                        {
+                            eollen = 1;
+                            if (i + 1 >= buf->offset)
+                                break;
+                            if (buf->data[i + 1] == '\n')
+                            {
+                                eollen = 2;
+                                break;
+                            }
+                        }
+                        // BUG: handle UTF PS and LS too
+                        if (c != '-')
+                            goto Lcont;
+                    }
+                    if (i - istart < 3)
+                        goto Lcont;
+
+                    // We have the start/end of a code section
+
+                    // Remove the entire --- line, including blanks and \n
+                    buf->remove(iLineStart, i - iLineStart + eollen);
+                    i = iLineStart;
+
+                    if (inCode && (i <= iCodeStart))
+                    {
+                        // Empty code section, just remove it completely.
+                        inCode = 0;
+                        break;
+                    }
+
+                    if (inCode)
+                    {
+                        inCode = 0;
+                        // The code section is from iCodeStart to i
+                        OutBuffer codebuf;
+
+                        codebuf.write(buf->data + iCodeStart, i - iCodeStart);
+                        codebuf.writeByte(0);
+
+                        // Remove leading indentations from all lines
+                        bool lineStart = true;
+                        utf8_t *endp = (utf8_t *)codebuf.data + codebuf.offset;
+                        for (utf8_t *p = (utf8_t *)codebuf.data; p < endp; )
+                        {
+                            if (lineStart)
+                            {
+                                size_t j = codeIndent;
+                                utf8_t *q = p;
+                                while (j-- > 0 && q < endp && isIndentWS(q))
+                                    ++q;
+                                codebuf.remove(p - (utf8_t *)codebuf.data, q - p);
+                                assert((utf8_t *)codebuf.data <= p);
+                                assert(p < (utf8_t *)codebuf.data + codebuf.offset);
+                                lineStart = false;
+                                endp = (utf8_t *)codebuf.data + codebuf.offset; // update
+                                continue;
+                            }
+                            if (*p == '\n')
+                                lineStart = true;
+                            ++p;
+                        }
+
+                        highlightCode2(sc, a, &codebuf, 0);
+                        buf->remove(iCodeStart, i - iCodeStart);
+                        i = buf->insert(iCodeStart, codebuf.data, codebuf.offset);
+                        i = buf->insert(i, (const char *)")\n", 2);
+                        i -= 2; // in next loop, c should be '\n'
+                    }
+                    else
+                    {
+                        static const char d_code[] = "$(D_CODE ";
+
+                        inCode = 1;
+                        codeIndent = istart - iLineStart;  // save indent count
+                        i = buf->insert(i, d_code, strlen(d_code));
+                        iCodeStart = i;
+                        i--;            // place i on >
+                        leadingBlank = true;
+                    }
+                }
+                break;
+
+            default:
+                leadingBlank = 0;
+                if (sc->_module->isDocFile || inCode)
+                    break;
+
+                utf8_t *start = (utf8_t *)buf->data + i;
+                if (isIdStart(start))
+                {
+                    size_t j = skippastident(buf, i);
+                    if (i < j)
+                    {
+                        size_t k = skippastURL(buf, i);
+                        if (i < k)
+                        {
+                            i = k - 1;
+                            break;
+                        }
+                    }
+                    else
+                        break;
+                    size_t len = j - i;
+
+                    // leading '_' means no highlight unless it's a reserved symbol name
+                    if (c == '_' &&
+                        (i == 0 || !isdigit(*(start - 1))) &&
+                        (i == buf->offset - 1 || !isReservedName(start, len)))
+                    {
+                        buf->remove(i, 1);
+                        i = j - 1;
+                        break;
+                    }
+                    if (isIdentifier(a, start, len))
+                    {
+                        i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1;
+                        break;
+                    }
+                    if (isKeyword(start, len))
+                    {
+                        i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1;
+                        break;
+                    }
+                    if (isFunctionParameter(a, start, len))
+                    {
+                        //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
+                        i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1;
+                        break;
+                    }
+
+                    i = j - 1;
+                }
+                break;
+        }
+    }
+    if (inCode)
+        error(s ? s->loc : Loc(), "unmatched --- in DDoc comment");
+}
+
+/**************************************************
+ * Highlight code for DDOC section.
+ */
+
+void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset)
+{
+    //printf("highlightCode(s = %s '%s')\n", s->kind(), s->toChars());
+    OutBuffer ancbuf;
+    emitAnchor(&ancbuf, s, sc);
+    buf->insert(offset, (char *)ancbuf.data, ancbuf.offset);
+    offset += ancbuf.offset;
+
+    Dsymbols a;
+    a.push(s);
+    highlightCode(sc, &a, buf, offset);
+}
+
+/****************************************************
+ */
+
+void highlightCode(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset)
+{
+    //printf("highlightCode(a = '%s')\n", a->toChars());
+
+    for (size_t i = offset; i < buf->offset; i++)
+    {
+        utf8_t c = buf->data[i];
+        const char *se = sc->_module->escapetable->escapeChar(c);
+        if (se)
+        {
+            size_t len = strlen(se);
+            buf->remove(i, 1);
+            i = buf->insert(i, se, len);
+            i--;                // point to ';'
+            continue;
+        }
+
+        utf8_t *start = (utf8_t *)buf->data + i;
+        if (isIdStart(start))
+        {
+            size_t j = skippastident(buf, i);
+            if (i < j)
+            {
+                size_t len = j - i;
+                if (isIdentifier(a, start, len))
+                {
+                    i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1;
+                    continue;
+                }
+                if (isFunctionParameter(a, start, len))
+                {
+                    //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
+                    i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1;
+                    continue;
+                }
+                i = j - 1;
+            }
+        }
+    }
+}
+
+/****************************************
+ */
+
+void highlightCode3(Scope *sc, OutBuffer *buf, const utf8_t *p, const utf8_t *pend)
+{
+    for (; p < pend; p++)
+    {
+        const char *s = sc->_module->escapetable->escapeChar(*p);
+        if (s)
+            buf->writestring(s);
+        else
+            buf->writeByte(*p);
+    }
+}
+
+/**************************************************
+ * Highlight code for CODE section.
+ */
+
+void highlightCode2(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset)
+{
+    unsigned errorsave = global.errors;
+    Lexer lex(NULL, (utf8_t *)buf->data, 0, buf->offset - 1, 0, 1);
+    OutBuffer res;
+    const utf8_t *lastp = (utf8_t *)buf->data;
+
+    //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data);
+    res.reserve(buf->offset);
+    while (1)
+    {
+        Token tok;
+        lex.scan(&tok);
+        highlightCode3(sc, &res, lastp, tok.ptr);
+
+        const char *highlight = NULL;
+        switch (tok.value)
+        {
+            case TOKidentifier:
+            {
+                if (!sc)
+                    break;
+                size_t len = lex.p - tok.ptr;
+                if (isIdentifier(a, tok.ptr, len))
+                {
+                    highlight = "$(D_PSYMBOL ";
+                    break;
+                }
+                if (isFunctionParameter(a, tok.ptr, len))
+                {
+                    //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
+                    highlight = "$(D_PARAM ";
+                    break;
+                }
+                break;
+            }
+            case TOKcomment:
+                highlight = "$(D_COMMENT ";
+                break;
+
+            case TOKstring:
+                highlight = "$(D_STRING ";
+                break;
+
+            default:
+                if (tok.isKeyword())
+                    highlight = "$(D_KEYWORD ";
+                break;
+        }
+        if (highlight)
+        {
+            res.writestring(highlight);
+            size_t o = res.offset;
+            highlightCode3(sc, &res, tok.ptr, lex.p);
+            if (tok.value == TOKcomment || tok.value == TOKstring)
+                escapeDdocString(&res, o);  // Bugzilla 7656, 7715, and 10519
+            res.writeByte(')');
+        }
+        else
+            highlightCode3(sc, &res, tok.ptr, lex.p);
+        if (tok.value == TOKeof)
+            break;
+        lastp = lex.p;
+    }
+    buf->setsize(offset);
+    buf->write(&res);
+    global.errors = errorsave;
+}
+
+/***************************************
+ * Find character string to replace c with.
+ */
+
+const char *Escape::escapeChar(unsigned c)
+{
+#if 1
+    assert(c < 256);
+    //printf("escapeChar('%c') => %p, %p\n", c, strings, strings[c]);
+    return strings[c];
+#else
+    const char *s;
+    switch (c)
+    {
+        case '<':
+            s = "&lt;";
+            break;
+        case '>':
+            s = "&gt;";
+            break;
+        case '&':
+            s = "&amp;";
+            break;
+        default:
+            s = NULL;
+            break;
+    }
+    return s;
+#endif
+}
+
+/****************************************
+ * Determine if p points to the start of a "..." parameter identifier.
+ */
+
+bool isCVariadicArg(const utf8_t *p, size_t len)
+{
+    return len >= 3 && cmp("...", p, 3) == 0;
+}
+
+/****************************************
+ * Determine if p points to the start of an identifier.
+ */
+
+bool isIdStart(const utf8_t *p)
+{
+    unsigned c = *p;
+    if (isalpha(c) || c == '_')
+        return true;
+    if (c >= 0x80)
+    {
+        size_t i = 0;
+        if (utf_decodeChar(p, 4, &i, &c))
+            return false;   // ignore errors
+        if (isUniAlpha(c))
+            return true;
+    }
+    return false;
+}
+
+/****************************************
+ * Determine if p points to the rest of an identifier.
+ */
+
+bool isIdTail(const utf8_t *p)
+{
+    unsigned c = *p;
+    if (isalnum(c) || c == '_')
+        return true;
+    if (c >= 0x80)
+    {
+        size_t i = 0;
+        if (utf_decodeChar(p, 4, &i, &c))
+            return false;   // ignore errors
+        if (isUniAlpha(c))
+            return true;
+    }
+    return false;
+}
+
+/****************************************
+ * Determine if p points to the indentation space.
+ */
+
+bool isIndentWS(const utf8_t *p)
+{
+    return (*p == ' ') || (*p == '\t');
+}
+
+/*****************************************
+ * Return number of bytes in UTF character.
+ */
+
+int utfStride(const utf8_t *p)
+{
+    unsigned c = *p;
+    if (c < 0x80)
+        return 1;
+    size_t i = 0;
+    utf_decodeChar(p, 4, &i, &c);       // ignore errors, but still consume input
+    return (int)i;
+}
diff --git a/gcc/d/dfrontend/doc.h b/gcc/d/dfrontend/doc.h
new file mode 100644
index 00000000000..92f9a79e720
--- /dev/null
+++ b/gcc/d/dfrontend/doc.h
@@ -0,0 +1,22 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/doc.h
+ */
+
+#ifndef DMD_DOC_H
+#define DMD_DOC_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+void escapeDdocString(OutBuffer *buf, size_t start);
+void gendocfile(Module *m);
+
+#endif
diff --git a/gcc/d/dfrontend/dscope.c b/gcc/d/dfrontend/dscope.c
new file mode 100644
index 00000000000..81ad922bcee
--- /dev/null
+++ b/gcc/d/dfrontend/dscope.c
@@ -0,0 +1,741 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/scope.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>                     // strlen()
+
+#include "root.h"
+#include "rmem.h"
+#include "speller.h"
+
+#include "mars.h"
+#include "init.h"
+#include "identifier.h"
+#include "scope.h"
+#include "attrib.h"
+#include "dsymbol.h"
+#include "declaration.h"
+#include "statement.h"
+#include "aggregate.h"
+#include "module.h"
+#include "id.h"
+#include "template.h"
+
+Scope *Scope::freelist = NULL;
+
+void allocFieldinit(Scope *sc, size_t dim)
+{
+    sc->fieldinit = (unsigned *)mem.xcalloc(sizeof(unsigned), dim);
+    sc->fieldinit_dim = dim;
+}
+
+void freeFieldinit(Scope *sc)
+{
+    if (sc->fieldinit)
+        mem.xfree(sc->fieldinit);
+    sc->fieldinit = NULL;
+    sc->fieldinit_dim = 0;
+}
+
+Scope *Scope::alloc()
+{
+    if (freelist)
+    {
+        Scope *s = freelist;
+        freelist = s->enclosing;
+        //printf("freelist %p\n", s);
+        assert(s->flags & SCOPEfree);
+        s->flags &= ~SCOPEfree;
+        return s;
+    }
+
+    return new Scope();
+}
+
+Scope::Scope()
+{
+    // Create root scope
+
+    //printf("Scope::Scope() %p\n", this);
+    this->_module = NULL;
+    this->scopesym = NULL;
+    this->sds = NULL;
+    this->enclosing = NULL;
+    this->parent = NULL;
+    this->sw = NULL;
+    this->tf = NULL;
+    this->os = NULL;
+    this->tinst = NULL;
+    this->minst = NULL;
+    this->sbreak = NULL;
+    this->scontinue = NULL;
+    this->fes = NULL;
+    this->callsc = NULL;
+    this->aligndecl = NULL;
+    this->func = NULL;
+    this->slabel = NULL;
+    this->linkage = LINKd;
+    this->cppmangle = CPPMANGLEdefault;
+    this->inlining = PINLINEdefault;
+    this->protection = Prot(PROTpublic);
+    this->explicitProtection = 0;
+    this->stc = 0;
+    this->depdecl = NULL;
+    this->inunion = 0;
+    this->nofree = 0;
+    this->noctor = 0;
+    this->intypeof = 0;
+    this->lastVar = NULL;
+    this->callSuper = 0;
+    this->fieldinit = NULL;
+    this->fieldinit_dim = 0;
+    this->flags = 0;
+    this->lastdc = NULL;
+    this->anchorCounts = NULL;
+    this->prevAnchor = NULL;
+    this->userAttribDecl = NULL;
+}
+
+Scope *Scope::copy()
+{
+    Scope *sc = Scope::alloc();
+    memcpy(sc, this, sizeof(Scope));
+
+    /* Bugzilla 11777: The copied scope should not inherit fieldinit.
+     */
+    sc->fieldinit = NULL;
+
+    return sc;
+}
+
+Scope *Scope::createGlobal(Module *_module)
+{
+    Scope *sc = Scope::alloc();
+    memset(sc, 0, sizeof(Scope));
+
+    sc->aligndecl = NULL;
+    sc->linkage = LINKd;
+    sc->inlining = PINLINEdefault;
+    sc->protection = Prot(PROTpublic);
+
+    sc->_module = _module;
+
+    sc->tinst = NULL;
+    sc->minst = _module;
+
+    sc->scopesym = new ScopeDsymbol();
+    sc->scopesym->symtab = new DsymbolTable();
+
+    // Add top level package as member of this global scope
+    Dsymbol *m = _module;
+    while (m->parent)
+        m = m->parent;
+    m->addMember(NULL, sc->scopesym);
+    m->parent = NULL;                   // got changed by addMember()
+
+    // Create the module scope underneath the global scope
+    sc = sc->push(_module);
+    sc->parent = _module;
+    return sc;
+}
+
+Scope *Scope::push()
+{
+    Scope *s = copy();
+
+    //printf("Scope::push(this = %p) new = %p\n", this, s);
+    assert(!(flags & SCOPEfree));
+    s->scopesym = NULL;
+    s->sds = NULL;
+    s->enclosing = this;
+#ifdef DEBUG
+    if (enclosing)
+        assert(!(enclosing->flags & SCOPEfree));
+    if (s == enclosing)
+    {
+        printf("this = %p, enclosing = %p, enclosing->enclosing = %p\n", s, this, enclosing);
+    }
+    assert(s != enclosing);
+#endif
+    s->slabel = NULL;
+    s->nofree = 0;
+    s->fieldinit = saveFieldInit();
+    s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint |
+                         SCOPEnoaccesscheck | SCOPEignoresymbolvisibility));
+    s->lastdc = NULL;
+
+    assert(this != s);
+    return s;
+}
+
+Scope *Scope::push(ScopeDsymbol *ss)
+{
+    //printf("Scope::push(%s)\n", ss->toChars());
+    Scope *s = push();
+    s->scopesym = ss;
+    return s;
+}
+
+Scope *Scope::pop()
+{
+    //printf("Scope::pop() %p nofree = %d\n", this, nofree);
+    Scope *enc = enclosing;
+
+    if (enclosing)
+    {
+        enclosing->callSuper |= callSuper;
+        if (fieldinit)
+        {
+            if (enclosing->fieldinit)
+            {
+                assert(fieldinit != enclosing->fieldinit);
+                size_t dim = fieldinit_dim;
+                for (size_t i = 0; i < dim; i++)
+                    enclosing->fieldinit[i] |= fieldinit[i];
+            }
+            freeFieldinit(this);
+        }
+    }
+
+    if (!nofree)
+    {
+        enclosing = freelist;
+        freelist = this;
+        flags |= SCOPEfree;
+    }
+
+    return enc;
+}
+
+Scope *Scope::startCTFE()
+{
+    Scope *sc = this->push();
+    sc->flags = this->flags | SCOPEctfe;
+#if 0
+    /* TODO: Currently this is not possible, because we need to
+     * unspeculative some types and symbols if they are necessary for the
+     * final executable. Consider:
+     *
+     * struct S(T) {
+     *   string toString() const { return "instantiated"; }
+     * }
+     * enum x = S!int();
+     * void main() {
+     *   // To call x.toString in runtime, compiler should unspeculative S!int.
+     *   assert(x.toString() == "instantiated");
+     * }
+     */
+
+    // If a template is instantiated from CT evaluated expression,
+    // compiler can elide its code generation.
+    sc->tinst = NULL;
+    sc->minst = NULL;
+#endif
+    return sc;
+}
+
+Scope *Scope::endCTFE()
+{
+    assert(flags & SCOPEctfe);
+    return pop();
+}
+
+void Scope::mergeCallSuper(Loc loc, unsigned cs)
+{
+    // This does a primitive flow analysis to support the restrictions
+    // regarding when and how constructors can appear.
+    // It merges the results of two paths.
+    // The two paths are callSuper and cs; the result is merged into callSuper.
+
+    if (cs != callSuper)
+    {
+        // Have ALL branches called a constructor?
+        int aAll = (cs        & (CSXthis_ctor | CSXsuper_ctor)) != 0;
+        int bAll = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0;
+
+        // Have ANY branches called a constructor?
+        bool aAny = (cs        & CSXany_ctor) != 0;
+        bool bAny = (callSuper & CSXany_ctor) != 0;
+
+        // Have any branches returned?
+        bool aRet = (cs        & CSXreturn) != 0;
+        bool bRet = (callSuper & CSXreturn) != 0;
+
+        // Have any branches halted?
+        bool aHalt = (cs        & CSXhalt) != 0;
+        bool bHalt = (callSuper & CSXhalt) != 0;
+
+        bool ok = true;
+
+        if (aHalt && bHalt)
+        {
+            callSuper = CSXhalt;
+        }
+        else if ((!aHalt && aRet && !aAny && bAny) ||
+                 (!bHalt && bRet && !bAny && aAny))
+        {
+            // If one has returned without a constructor call, there must be never
+            // have been ctor calls in the other.
+            ok = false;
+        }
+        else if (aHalt || aRet && aAll)
+        {
+            // If one branch has called a ctor and then exited, anything the
+            // other branch has done is OK (except returning without a
+            // ctor call, but we already checked that).
+            callSuper |= cs & (CSXany_ctor | CSXlabel);
+        }
+        else if (bHalt || bRet && bAll)
+        {
+            callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel));
+        }
+        else
+        {
+            // Both branches must have called ctors, or both not.
+            ok = (aAll == bAll);
+            // If one returned without a ctor, we must remember that
+            // (Don't bother if we've already found an error)
+            if (ok && aRet && !aAny)
+                callSuper |= CSXreturn;
+            callSuper |= cs & (CSXany_ctor | CSXlabel);
+        }
+        if (!ok)
+            error(loc, "one path skips constructor");
+    }
+}
+
+unsigned *Scope::saveFieldInit()
+{
+    unsigned *fi = NULL;
+    if (fieldinit)  // copy
+    {
+        size_t dim = fieldinit_dim;
+        fi = (unsigned *)mem.xmalloc(sizeof(unsigned) * dim);
+        for (size_t i = 0; i < dim; i++)
+            fi[i] = fieldinit[i];
+    }
+    return fi;
+}
+
+bool mergeFieldInit(Loc loc, unsigned &fieldInit, unsigned fi, bool mustInit)
+{
+    if (fi != fieldInit)
+    {
+        // Have any branches returned?
+        bool aRet = (fi        & CSXreturn) != 0;
+        bool bRet = (fieldInit & CSXreturn) != 0;
+
+        // Have any branches halted?
+        bool aHalt = (fi        & CSXhalt) != 0;
+        bool bHalt = (fieldInit & CSXhalt) != 0;
+
+        bool ok;
+
+        if (aHalt && bHalt)
+        {
+            ok = true;
+            fieldInit = CSXhalt;
+        }
+        else if (!aHalt && aRet)
+        {
+            ok = !mustInit || (fi & CSXthis_ctor);
+            fieldInit = fieldInit;
+        }
+        else if (!bHalt && bRet)
+        {
+            ok = !mustInit || (fieldInit & CSXthis_ctor);
+            fieldInit = fi;
+        }
+        else if (aHalt)
+        {
+            ok = !mustInit || (fieldInit & CSXthis_ctor);
+            fieldInit = fieldInit;
+        }
+        else if (bHalt)
+        {
+            ok = !mustInit || (fi & CSXthis_ctor);
+            fieldInit = fi;
+        }
+        else
+        {
+            ok = !mustInit || !((fieldInit ^ fi) & CSXthis_ctor);
+            fieldInit |= fi;
+        }
+
+        return ok;
+    }
+    return true;
+}
+
+void Scope::mergeFieldInit(Loc loc, unsigned *fies)
+{
+    if (fieldinit && fies)
+    {
+        FuncDeclaration *f = func;
+        if (fes) f = fes->func;
+        AggregateDeclaration *ad = f->isMember2();
+        assert(ad);
+
+        for (size_t i = 0; i < ad->fields.dim; i++)
+        {
+            VarDeclaration *v = ad->fields[i];
+            bool mustInit = (v->storage_class & STCnodefaultctor ||
+                             v->type->needsNested());
+
+            if (!::mergeFieldInit(loc, fieldinit[i], fies[i], mustInit))
+            {
+                ::error(loc, "one path skips field %s", ad->fields[i]->toChars());
+            }
+        }
+    }
+}
+
+Module *Scope::instantiatingModule()
+{
+    // TODO: in speculative context, returning 'module' is correct?
+    return minst ? minst : _module;
+}
+
+static Dsymbol *searchScopes(Scope *scope, Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
+{
+    for (Scope *sc = scope; sc; sc = sc->enclosing)
+    {
+        assert(sc != sc->enclosing);
+        if (!sc->scopesym)
+            continue;
+        //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc->scopesym->toChars(), sc->scopesym->kind(), flags);
+
+        if (sc->scopesym->isModule())
+            flags |= SearchUnqualifiedModule;        // tell Module.search() that SearchLocalsOnly is to be obeyed
+
+        if (Dsymbol *s = sc->scopesym->search(loc, ident, flags))
+        {
+            if (!(flags & (SearchImportsOnly | IgnoreErrors)) &&
+                ident == Id::length && sc->scopesym->isArrayScopeSymbol() &&
+                sc->enclosing && sc->enclosing->search(loc, ident, NULL, flags))
+            {
+                warning(s->loc, "array 'length' hides other 'length' name in outer scope");
+            }
+#ifdef LOGSEARCH
+            printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind());
+#endif
+            if (pscopesym)
+                *pscopesym = sc->scopesym;
+            return s;
+        }
+        // Stop when we hit a module, but keep going if that is not just under the global scope
+        if (sc->scopesym->isModule() && !(sc->enclosing && !sc->enclosing->enclosing))
+            break;
+    }
+    return NULL;
+}
+
+/************************************
+ * Perform unqualified name lookup by following the chain of scopes up
+ * until found.
+ *
+ * Params:
+ *  loc = location to use for error messages
+ *  ident = name to look up
+ *  pscopesym = if supplied and name is found, set to scope that ident was found in
+ *  flags = modify search based on flags
+ *
+ * Returns:
+ *  symbol if found, null if not
+ */
+Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
+{
+#ifdef LOGSEARCH
+    printf("Scope::search(%p, '%s' flags=x%x)\n", this, ident->toChars(), flags);
+    // Print scope chain
+    for (Scope *sc = this; sc; sc = sc->enclosing)
+    {
+        if (!sc->scopesym)
+            continue;
+        printf("\tscope %s\n", sc->scopesym->toChars());
+    }
+#endif
+
+    // This function is called only for unqualified lookup
+    assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
+
+    /* If ident is "start at module scope", only look at module scope
+     */
+    if (ident == Id::empty)
+    {
+        // Look for module scope
+        for (Scope *sc = this; sc; sc = sc->enclosing)
+        {
+            assert(sc != sc->enclosing);
+            if (!sc->scopesym)
+                continue;
+
+            if (Dsymbol *s = sc->scopesym->isModule())
+            {
+#ifdef LOGSEARCH
+                printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind());
+#endif
+                if (pscopesym)
+                    *pscopesym = sc->scopesym;
+                return s;
+            }
+        }
+        return NULL;
+    }
+
+    if (this->flags & SCOPEignoresymbolvisibility)
+        flags |= IgnoreSymbolVisibility;
+
+    Dsymbol *sold = NULL;
+    if (global.params.bug10378 || global.params.check10378)
+    {
+        sold = searchScopes(this, loc, ident, pscopesym, flags | IgnoreSymbolVisibility);
+        if (!global.params.check10378)
+            return sold;
+
+        if (ident == Id::dollar) // Bugzilla 15825
+            return sold;
+
+        // Search both ways
+    }
+
+    // First look in local scopes
+    Dsymbol *s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly);
+#ifdef LOGSEARCH
+    if (s)
+        printf("\t-Scope::search() found local %s.%s, kind = '%s'\n",
+               s->parent ? s->parent->toChars() : "", s->toChars(), s->kind());
+#endif
+    if (!s)
+    {
+        // Second look in imported modules
+        s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly);
+#ifdef LOGSEARCH
+        if (s)
+            printf("\t-Scope::search() found import %s.%s, kind = '%s'\n",
+                   s->parent ? s->parent->toChars() : "", s->toChars(), s->kind());
+#endif
+
+        /** Still find private symbols, so that symbols that weren't access
+         * checked by the compiler remain usable.  Once the deprecation is over,
+         * this should be moved to search_correct instead.
+         */
+        if (!s && !(flags & IgnoreSymbolVisibility))
+        {
+            s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly | IgnoreSymbolVisibility);
+            if (!s)
+                s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly | IgnoreSymbolVisibility);
+
+            if (s && !(flags & IgnoreErrors))
+                ::deprecation(loc, "%s is not visible from module %s", s->toPrettyChars(), _module->toChars());
+#ifdef LOGSEARCH
+            if (s)
+                printf("\t-Scope::search() found imported private symbol%s.%s, kind = '%s'\n",
+                       s->parent ? s->parent->toChars() : "", s->toChars(), s->kind());
+#endif
+        }
+    }
+
+    if (global.params.check10378)
+    {
+        Dsymbol *snew = s;
+        if (sold != snew)
+            deprecation10378(loc, sold, snew);
+        if (global.params.bug10378)
+            s = sold;
+    }
+    return s;
+}
+
+Dsymbol *Scope::insert(Dsymbol *s)
+{
+    if (VarDeclaration *vd = s->isVarDeclaration())
+    {
+        if (lastVar)
+            vd->lastVar = lastVar;
+        lastVar = vd;
+    }
+    else if (WithScopeSymbol *ss = s->isWithScopeSymbol())
+    {
+        if (VarDeclaration *vd = ss->withstate->wthis)
+        {
+            if (lastVar)
+                vd->lastVar = lastVar;
+            lastVar = vd;
+        }
+        return NULL;
+    }
+    for (Scope *sc = this; sc; sc = sc->enclosing)
+    {
+        //printf("\tsc = %p\n", sc);
+        if (sc->scopesym)
+        {
+            //printf("\t\tsc->scopesym = %p\n", sc->scopesym);
+            if (!sc->scopesym->symtab)
+                sc->scopesym->symtab = new DsymbolTable();
+            return sc->scopesym->symtabInsert(s);
+        }
+    }
+    assert(0);
+    return NULL;
+}
+
+/********************************************
+ * Search enclosing scopes for ClassDeclaration.
+ */
+
+ClassDeclaration *Scope::getClassScope()
+{
+    for (Scope *sc = this; sc; sc = sc->enclosing)
+    {
+        if (!sc->scopesym)
+            continue;
+
+        ClassDeclaration *cd = sc->scopesym->isClassDeclaration();
+        if (cd)
+            return cd;
+    }
+    return NULL;
+}
+
+/********************************************
+ * Search enclosing scopes for ClassDeclaration.
+ */
+
+AggregateDeclaration *Scope::getStructClassScope()
+{
+    for (Scope *sc = this; sc; sc = sc->enclosing)
+    {
+        if (!sc->scopesym)
+            continue;
+
+        AggregateDeclaration *ad = sc->scopesym->isClassDeclaration();
+        if (ad)
+            return ad;
+        ad = sc->scopesym->isStructDeclaration();
+        if (ad)
+            return ad;
+    }
+    return NULL;
+}
+
+/*******************************************
+ * For TemplateDeclarations, we need to remember the Scope
+ * where it was declared. So mark the Scope as not
+ * to be free'd.
+ */
+
+void Scope::setNoFree()
+{
+    //int i = 0;
+
+    //printf("Scope::setNoFree(this = %p)\n", this);
+    for (Scope *sc = this; sc; sc = sc->enclosing)
+    {
+        //printf("\tsc = %p\n", sc);
+        sc->nofree = 1;
+
+        assert(!(flags & SCOPEfree));
+        //assert(sc != sc->enclosing);
+        //assert(!sc->enclosing || sc != sc->enclosing->enclosing);
+        //if (++i == 10)
+            //assert(0);
+    }
+}
+
+structalign_t Scope::alignment()
+{
+    if (aligndecl)
+        return aligndecl->getAlignment();
+    else
+        return STRUCTALIGN_DEFAULT;
+}
+
+/************************************************
+ * Given the failed search attempt, try to find
+ * one with a close spelling.
+ */
+
+void *scope_search_fp(void *arg, const char *seed, int* cost)
+{
+    //printf("scope_search_fp('%s')\n", seed);
+
+    /* If not in the lexer's string table, it certainly isn't in the symbol table.
+     * Doing this first is a lot faster.
+     */
+    size_t len = strlen(seed);
+    if (!len)
+        return NULL;
+    Identifier *id = Identifier::lookup(seed, len);
+    if (!id)
+        return NULL;
+
+    Scope *sc = (Scope *)arg;
+    Module::clearCache();
+    Dsymbol *scopesym = NULL;
+    Dsymbol *s = sc->search(Loc(), id, &scopesym, IgnoreErrors);
+    if (s)
+    {
+        for (*cost = 0; sc; sc = sc->enclosing, (*cost)++)
+            if (sc->scopesym == scopesym)
+                break;
+        if (scopesym != s->parent)
+        {
+            (*cost)++; // got to the symbol through an import
+            if (s->prot().kind == PROTprivate)
+                return NULL;
+        }
+    }
+    return (void*)s;
+}
+
+void Scope::deprecation10378(Loc loc, Dsymbol *sold, Dsymbol *snew)
+{
+    // Bugzilla 15857
+    //
+    // The overloadset found via the new lookup rules is either
+    // equal or a subset of the overloadset found via the old
+    // lookup rules, so it suffices to compare the dimension to
+    // check for equality.
+    OverloadSet *osold = NULL;
+    OverloadSet *osnew = NULL;
+    if (sold && (osold = sold->isOverloadSet()) != NULL &&
+        snew && (osnew = snew->isOverloadSet()) != NULL &&
+        osold->a.dim == osnew->a.dim)
+        return;
+
+    OutBuffer buf;
+    buf.writestring("local import search method found ");
+    if (osold)
+        buf.printf("%s %s (%d overloads)", sold->kind(), sold->toPrettyChars(), (int)osold->a.dim);
+    else if (sold)
+        buf.printf("%s %s", sold->kind(), sold->toPrettyChars());
+    else
+        buf.writestring("nothing");
+    buf.writestring(" instead of ");
+    if (osnew)
+        buf.printf("%s %s (%d overloads)", snew->kind(), snew->toPrettyChars(), (int)osnew->a.dim);
+    else if (snew)
+        buf.printf("%s %s", snew->kind(), snew->toPrettyChars());
+    else
+        buf.writestring("nothing");
+
+    deprecation(loc, buf.peekString());
+}
+
+Dsymbol *Scope::search_correct(Identifier *ident)
+{
+    if (global.gag)
+        return NULL;            // don't do it for speculative compiles; too time consuming
+
+    return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars);
+}
diff --git a/gcc/d/dfrontend/dstruct.c b/gcc/d/dfrontend/dstruct.c
new file mode 100644
index 00000000000..7bd7cdcf0c8
--- /dev/null
+++ b/gcc/d/dfrontend/dstruct.c
@@ -0,0 +1,1472 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/struct.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "mtype.h"
+#include "init.h"
+#include "declaration.h"
+#include "module.h"
+#include "id.h"
+#include "statement.h"
+#include "template.h"
+#include "tokens.h"
+
+Type *getTypeInfoType(Type *t, Scope *sc);
+TypeTuple *toArgTypes(Type *t);
+void unSpeculative(Scope *sc, RootObject *o);
+bool MODimplicitConv(MOD modfrom, MOD modto);
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+
+FuncDeclaration *StructDeclaration::xerreq;     // object.xopEquals
+FuncDeclaration *StructDeclaration::xerrcmp;    // object.xopCmp
+
+/***************************************
+ * Search toString member function for TypeInfo_Struct.
+ *      string toString();
+ */
+FuncDeclaration *search_toString(StructDeclaration *sd)
+{
+    Dsymbol *s = search_function(sd, Id::tostring);
+    FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
+    if (fd)
+    {
+        static TypeFunction *tftostring;
+        if (!tftostring)
+        {
+            tftostring = new TypeFunction(NULL, Type::tstring, 0, LINKd);
+            tftostring = (TypeFunction *)tftostring->merge();
+        }
+
+        fd = fd->overloadExactMatch(tftostring);
+    }
+    return fd;
+}
+
+/***************************************
+ * Request additonal semantic analysis for TypeInfo generation.
+ */
+void semanticTypeInfo(Scope *sc, Type *t)
+{
+    class FullTypeInfoVisitor : public Visitor
+    {
+    public:
+        Scope *sc;
+
+        void visit(Type *t)
+        {
+            Type *tb = t->toBasetype();
+            if (tb != t)
+                tb->accept(this);
+        }
+        void visit(TypeNext *t)
+        {
+            if (t->next)
+                t->next->accept(this);
+        }
+        void visit(TypeBasic *t) { }
+        void visit(TypeVector *t)
+        {
+            t->basetype->accept(this);
+        }
+        void visit(TypeAArray *t)
+        {
+            t->index->accept(this);
+            visit((TypeNext *)t);
+        }
+        void visit(TypeFunction *t)
+        {
+            visit((TypeNext *)t);
+            // Currently TypeInfo_Function doesn't store parameter types.
+        }
+        void visit(TypeStruct *t)
+        {
+            StructDeclaration *sd = t->sym;
+
+            /* Step 1: create TypeInfoDeclaration
+             */
+            if (!sc) // inline may request TypeInfo.
+            {
+                Scope scx;
+                scx._module = sd->getModule();
+                getTypeInfoType(t, &scx);
+                sd->requestTypeInfo = true;
+            }
+            else if (!sc->minst)
+            {
+                // don't yet have to generate TypeInfo instance if
+                // the typeid(T) expression exists in speculative scope.
+            }
+            else
+            {
+                getTypeInfoType(t, sc);
+                sd->requestTypeInfo = true;
+
+                // Bugzilla 15149, if the typeid operand type comes from a
+                // result of auto function, it may be yet speculative.
+                unSpeculative(sc, sd);
+            }
+
+            /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
+             * This should be done even if typeid(T) exists in speculative scope.
+             * Because it may appear later in non-speculative scope.
+             */
+            if (!sd->members)
+                return;     // opaque struct
+            if (!sd->xeq && !sd->xcmp && !sd->postblit &&
+                !sd->dtor && !sd->xhash && !search_toString(sd))
+                return;     // none of TypeInfo-specific members
+
+            // If the struct is in a non-root module, run semantic3 to get
+            // correct symbols for the member function.
+            if (sd->semanticRun >= PASSsemantic3)
+            {
+                // semantic3 is already done
+            }
+            else if (TemplateInstance *ti = sd->isInstantiated())
+            {
+                if (ti->minst && !ti->minst->isRoot())
+                    Module::addDeferredSemantic3(sd);
+            }
+            else
+            {
+                if (sd->inNonRoot())
+                {
+                    //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd->toChars(), sd->inNonRoot());
+                    Module::addDeferredSemantic3(sd);
+                }
+            }
+        }
+        void visit(TypeClass *t) { }
+        void visit(TypeTuple *t)
+        {
+            if (t->arguments)
+            {
+                for (size_t i = 0; i < t->arguments->dim; i++)
+                {
+                    Type *tprm = (*t->arguments)[i]->type;
+                    if (tprm)
+                        tprm->accept(this);
+                }
+            }
+        }
+    };
+
+    if (sc)
+    {
+        if (!sc->func)
+            return;
+        if (!sc->intypeof)
+            return;
+        if (sc->flags & (SCOPEctfe | SCOPEcompile))
+            return;
+    }
+
+    FullTypeInfoVisitor v;
+    v.sc = sc;
+    t->accept(&v);
+}
+
+/********************************* AggregateDeclaration ****************************/
+
+AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
+    : ScopeDsymbol(id)
+{
+    this->loc = loc;
+
+    storage_class = 0;
+    protection = Prot(PROTpublic);
+    type = NULL;
+    structsize = 0;             // size of struct
+    alignsize = 0;              // size of struct for alignment purposes
+    sizeok = SIZEOKnone;        // size not determined yet
+    deferred = NULL;
+    isdeprecated = false;
+    inv = NULL;
+    aggNew = NULL;
+    aggDelete = NULL;
+
+    stag = NULL;
+    sinit = NULL;
+    enclosing = NULL;
+    vthis = NULL;
+
+    ctor = NULL;
+    defaultCtor = NULL;
+    aliasthis = NULL;
+    noDefaultCtor = false;
+    dtor = NULL;
+    getRTInfo = NULL;
+}
+
+Prot AggregateDeclaration::prot()
+{
+    return protection;
+}
+
+/***************************************
+ * Create a new scope from sc.
+ * semantic, semantic2 and semantic3 will use this for aggregate members.
+ */
+Scope *AggregateDeclaration::newScope(Scope *sc)
+{
+    Scope *sc2 = sc->push(this);
+    sc2->stc &= STCsafe | STCtrusted | STCsystem;
+    sc2->parent = this;
+    if (isUnionDeclaration())
+        sc2->inunion = 1;
+    sc2->protection = Prot(PROTpublic);
+    sc2->explicitProtection = 0;
+    sc2->aligndecl = NULL;
+    sc2->userAttribDecl = NULL;
+    return sc2;
+}
+
+void AggregateDeclaration::setScope(Scope *sc)
+{
+    // Might need a scope to resolve forward references. The check for
+    // semanticRun prevents unnecessary setting of _scope during deferred
+    // setScope phases for aggregates which already finished semantic().
+    // Also see https://issues.dlang.org/show_bug.cgi?id=16607
+    if (semanticRun < PASSsemanticdone)
+        ScopeDsymbol::setScope(sc);
+}
+
+void AggregateDeclaration::semantic2(Scope *sc)
+{
+    //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", toChars(), type->toChars(), errors);
+    if (!members)
+        return;
+
+    if (_scope)
+    {
+        error("has forward references");
+        return;
+    }
+
+    Scope *sc2 = newScope(sc);
+
+    determineSize(loc);
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        //printf("\t[%d] %s\n", i, s->toChars());
+        s->semantic2(sc2);
+    }
+
+    sc2->pop();
+}
+
+void AggregateDeclaration::semantic3(Scope *sc)
+{
+    //printf("AggregateDeclaration::semantic3(%s) type = %s, errors = %d\n", toChars(), type->toChars(), errors);
+    if (!members)
+        return;
+
+    StructDeclaration *sd = isStructDeclaration();
+    if (!sc)    // from runDeferredSemantic3 for TypeInfo generation
+    {
+        assert(sd);
+        sd->semanticTypeInfoMembers();
+        return;
+    }
+
+    Scope *sc2 = newScope(sc);
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->semantic3(sc2);
+    }
+
+    sc2->pop();
+
+    // don't do it for unused deprecated types
+    // or error types
+    if (!getRTInfo && Type::rtinfo &&
+        (!isDeprecated() || global.params.useDeprecated) &&
+        (type && type->ty != Terror))
+    {
+        // Evaluate: RTinfo!type
+        Objects *tiargs = new Objects();
+        tiargs->push(type);
+        TemplateInstance *ti = new TemplateInstance(loc, Type::rtinfo, tiargs);
+
+        Scope *sc3 = ti->tempdecl->_scope->startCTFE();
+        sc3->tinst = sc->tinst;
+        sc3->minst = sc->minst;
+        if (isDeprecated())
+            sc3->stc |= STCdeprecated;
+
+        ti->semantic(sc3);
+        ti->semantic2(sc3);
+        ti->semantic3(sc3);
+        Expression *e = resolve(Loc(), sc3, ti->toAlias(), false);
+
+        sc3->endCTFE();
+
+        e = e->ctfeInterpret();
+        getRTInfo = e;
+    }
+
+    if (sd)
+        sd->semanticTypeInfoMembers();
+}
+
+/***************************************
+ * Find all instance fields, then push them into `fields`.
+ *
+ * Runs semantic() for all instance field variables, but also
+ * the field types can reamin yet not resolved forward references,
+ * except direct recursive definitions.
+ * After the process sizeok is set to SIZEOKfwd.
+ *
+ * Returns:
+ *      false if any errors occur.
+ */
+bool AggregateDeclaration::determineFields()
+{
+    if (sizeok != SIZEOKnone)
+        return true;
+
+    //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim);
+    fields.setDim(0);
+
+    struct SV
+    {
+        AggregateDeclaration *agg;
+
+        static int func(Dsymbol *s, void *param)
+        {
+            VarDeclaration *v = s->isVarDeclaration();
+            if (!v)
+                return 0;
+            if (v->storage_class & STCmanifest)
+                return 0;
+
+            AggregateDeclaration *ad = ((SV *)param)->agg;
+
+            if (v->_scope)
+                v->semantic(NULL);
+            // Note: Aggregate fields or size could have determined during v->semantic.
+            if (ad->sizeok != SIZEOKnone)
+                return 1;
+
+            if (v->aliassym)
+                return 0;   // If this variable was really a tuple, skip it.
+
+            if (v->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCctfe | STCtemplateparameter))
+                return 0;
+            if (!v->isField() || v->semanticRun < PASSsemanticdone)
+                return 1;   // unresolvable forward reference
+
+            ad->fields.push(v);
+
+            if (v->storage_class & STCref)
+                return 0;
+            Type *tv = v->type->baseElemOf();
+            if (tv->ty != Tstruct)
+                return 0;
+            if (ad == ((TypeStruct *)tv)->sym)
+            {
+                const char *psz = (v->type->toBasetype()->ty == Tsarray) ? "static array of " : "";
+                ad->error("cannot have field %s with %ssame struct type", v->toChars(), psz);
+                ad->type = Type::terror;
+                ad->errors = true;
+                return 1;
+            }
+            return 0;
+        }
+    };
+    SV sv;
+    sv.agg = this;
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        if (s->apply(&SV::func, &sv))
+        {
+            if (sizeok != SIZEOKnone)
+                return true;
+            return false;
+        }
+    }
+
+    if (sizeok != SIZEOKdone)
+        sizeok = SIZEOKfwd;
+
+    return true;
+}
+
+/***************************************
+ * Collect all instance fields, then determine instance size.
+ * Returns:
+ *      false if failed to determine the size.
+ */
+bool AggregateDeclaration::determineSize(Loc loc)
+{
+    //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
+
+    // The previous instance size finalizing had:
+    if (type->ty == Terror)
+        return false;   // failed already
+    if (sizeok == SIZEOKdone)
+        return true;    // succeeded
+
+    if (!members)
+    {
+        error(loc, "unknown size");
+        return false;
+    }
+
+    if (_scope)
+        semantic(NULL);
+
+    // Determine the instance size of base class first.
+    if (ClassDeclaration *cd = isClassDeclaration())
+    {
+        cd = cd->baseClass;
+        if (cd && !cd->determineSize(loc))
+            goto Lfail;
+    }
+
+    // Determine instance fields when sizeok == SIZEOKnone
+    if (!determineFields())
+        goto Lfail;
+    if (sizeok != SIZEOKdone)
+        finalizeSize();
+
+    // this aggregate type has:
+    if (type->ty == Terror)
+        return false;   // marked as invalid during the finalizing.
+    if (sizeok == SIZEOKdone)
+        return true;    // succeeded to calculate instance size.
+
+Lfail:
+    // There's unresolvable forward reference.
+    if (type != Type::terror)
+        error(loc, "no size because of forward reference");
+    // Don't cache errors from speculative semantic, might be resolvable later.
+    // https://issues.dlang.org/show_bug.cgi?id=16574
+    if (!global.gag)
+    {
+        type = Type::terror;
+        errors = true;
+    }
+    return false;
+}
+
+void StructDeclaration::semanticTypeInfoMembers()
+{
+    if (xeq &&
+        xeq->_scope &&
+        xeq->semanticRun < PASSsemantic3done)
+    {
+        unsigned errors = global.startGagging();
+        xeq->semantic3(xeq->_scope);
+        if (global.endGagging(errors))
+            xeq = xerreq;
+    }
+
+    if (xcmp &&
+        xcmp->_scope &&
+        xcmp->semanticRun < PASSsemantic3done)
+    {
+        unsigned errors = global.startGagging();
+        xcmp->semantic3(xcmp->_scope);
+        if (global.endGagging(errors))
+            xcmp = xerrcmp;
+    }
+
+    FuncDeclaration *ftostr = search_toString(this);
+    if (ftostr &&
+        ftostr->_scope &&
+        ftostr->semanticRun < PASSsemantic3done)
+    {
+        ftostr->semantic3(ftostr->_scope);
+    }
+
+    if (xhash &&
+        xhash->_scope &&
+        xhash->semanticRun < PASSsemantic3done)
+    {
+        xhash->semantic3(xhash->_scope);
+    }
+
+    if (postblit &&
+        postblit->_scope &&
+        postblit->semanticRun < PASSsemantic3done)
+    {
+        postblit->semantic3(postblit->_scope);
+    }
+
+    if (dtor &&
+        dtor->_scope &&
+        dtor->semanticRun < PASSsemantic3done)
+    {
+        dtor->semantic3(dtor->_scope);
+    }
+}
+
+d_uns64 AggregateDeclaration::size(Loc loc)
+{
+    //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
+    bool ok = determineSize(loc);
+    //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
+    return ok ? structsize : SIZE_INVALID;
+}
+
+Type *AggregateDeclaration::getType()
+{
+    return type;
+}
+
+bool AggregateDeclaration::isDeprecated()
+{
+    return isdeprecated;
+}
+
+bool AggregateDeclaration::isExport()
+{
+    return protection.kind == PROTexport;
+}
+
+/***************************************
+ * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
+ * field initializers have unique memory space on instance.
+ * Returns:
+ *      true if any errors happen.
+ */
+
+bool AggregateDeclaration::checkOverlappedFields()
+{
+    //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
+    assert(sizeok == SIZEOKdone);
+    size_t nfields = fields.dim;
+    if (isNested())
+    {
+        ClassDeclaration *cd = isClassDeclaration();
+        if (!cd || !cd->baseClass || !cd->baseClass->isNested())
+            nfields--;
+    }
+    bool errors = false;
+
+    // Fill in missing any elements with default initializers
+    for (size_t i = 0; i < nfields; i++)
+    {
+        VarDeclaration *vd = fields[i];
+        if (vd->errors)
+        {
+            errors = true;
+            continue;
+        }
+
+        VarDeclaration *vx = vd;
+        if (vd->_init && vd->_init->isVoidInitializer())
+            vx = NULL;
+
+        // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
+        for (size_t j = 0; j < nfields; j++)
+        {
+            if (i == j)
+                continue;
+            VarDeclaration *v2 = fields[j];
+            if (v2->errors)
+            {
+                errors = true;
+                continue;
+            }
+            if (!vd->isOverlappedWith(v2))
+                continue;
+
+            // vd and v2 are overlapping.
+            vd->overlapped = true;
+            v2->overlapped = true;
+
+            if (!MODimplicitConv(vd->type->mod, v2->type->mod))
+                v2->overlapUnsafe = true;
+            if (!MODimplicitConv(v2->type->mod, vd->type->mod))
+                vd->overlapUnsafe = true;
+
+            if (!vx)
+                continue;
+            if (v2->_init && v2->_init->isVoidInitializer())
+                continue;
+
+            if (vx->_init && v2->_init)
+            {
+                ::error(loc, "overlapping default initialization for field %s and %s", v2->toChars(), vd->toChars());
+                errors = true;
+            }
+        }
+    }
+    return errors;
+}
+
+/***************************************
+ * Fill out remainder of elements[] with default initializers for fields[].
+ * Input:
+ *      loc:        location
+ *      elements:   explicit arguments which given to construct object.
+ *      ctorinit:   true if the elements will be used for default initialization.
+ * Returns:
+ *      false if any errors occur.
+ *      Otherwise, returns true and the missing arguments will be pushed in elements[].
+ */
+bool AggregateDeclaration::fill(Loc loc, Expressions *elements, bool ctorinit)
+{
+    //printf("AggregateDeclaration::fill() %s\n", toChars());
+    assert(sizeok == SIZEOKdone);
+    assert(elements);
+    size_t nfields = fields.dim - isNested();
+    bool errors = false;
+
+    size_t dim = elements->dim;
+    elements->setDim(nfields);
+    for (size_t i = dim; i < nfields; i++)
+        (*elements)[i] = NULL;
+
+    // Fill in missing any elements with default initializers
+    for (size_t i = 0; i < nfields; i++)
+    {
+        if ((*elements)[i])
+            continue;
+
+        VarDeclaration *vd = fields[i];
+        VarDeclaration *vx = vd;
+        if (vd->_init && vd->_init->isVoidInitializer())
+            vx = NULL;
+
+        // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
+        size_t fieldi = i;
+        for (size_t j = 0; j < nfields; j++)
+        {
+            if (i == j)
+                continue;
+            VarDeclaration *v2 = fields[j];
+            if (!vd->isOverlappedWith(v2))
+                continue;
+
+            if ((*elements)[j])
+            {
+                vx = NULL;
+                break;
+            }
+            if (v2->_init && v2->_init->isVoidInitializer())
+                continue;
+
+            if (1)
+            {
+                /* Prefer first found non-void-initialized field
+                 * union U { int a; int b = 2; }
+                 * U u;    // Error: overlapping initialization for field a and b
+                 */
+                if (!vx)
+                {
+                    vx = v2;
+                    fieldi = j;
+                }
+                else if (v2->_init)
+                {
+                    ::error(loc, "overlapping initialization for field %s and %s",
+                        v2->toChars(), vd->toChars());
+                    errors = true;
+                }
+            }
+            else
+            {
+                // Will fix Bugzilla 1432 by enabling this path always
+
+                /* Prefer explicitly initialized field
+                 * union U { int a; int b = 2; }
+                 * U u;    // OK (u.b == 2)
+                 */
+                if (!vx || !vx->_init && v2->_init)
+                {
+                    vx = v2;
+                    fieldi = j;
+                }
+                else if (vx != vd && !vx->isOverlappedWith(v2))
+                {
+                    // Both vx and v2 fills vd, but vx and v2 does not overlap
+                }
+                else if (vx->_init && v2->_init)
+                {
+                    ::error(loc, "overlapping default initialization for field %s and %s",
+                        v2->toChars(), vd->toChars());
+                    errors = true;
+                }
+                else
+                    assert(vx->_init || !vx->_init && !v2->_init);
+            }
+        }
+        if (vx)
+        {
+            Expression *e;
+            if (vx->type->size() == 0)
+            {
+                e = NULL;
+            }
+            else if (vx->_init)
+            {
+                assert(!vx->_init->isVoidInitializer());
+                e = vx->getConstInitializer(false);
+            }
+            else
+            {
+                if ((vx->storage_class & STCnodefaultctor) && !ctorinit)
+                {
+                    ::error(loc, "field %s.%s must be initialized because it has no default constructor",
+                            type->toChars(), vx->toChars());
+                    errors = true;
+                }
+
+                /* Bugzilla 12509: Get the element of static array type.
+                 */
+                Type *telem = vx->type;
+                if (telem->ty == Tsarray)
+                {
+                    /* We cannot use Type::baseElemOf() here.
+                     * If the bottom of the Tsarray is an enum type, baseElemOf()
+                     * will return the base of the enum, and its default initializer
+                     * would be different from the enum's.
+                     */
+                    while (telem->toBasetype()->ty == Tsarray)
+                        telem = ((TypeSArray *)telem->toBasetype())->next;
+
+                    if (telem->ty == Tvoid)
+                        telem = Type::tuns8->addMod(telem->mod);
+                }
+                if (telem->needsNested() && ctorinit)
+                    e = telem->defaultInit(loc);
+                else
+                    e = telem->defaultInitLiteral(loc);
+            }
+            (*elements)[fieldi] = e;
+        }
+    }
+
+    for (size_t i = 0; i < elements->dim; i++)
+    {
+        Expression *e = (*elements)[i];
+        if (e && e->op == TOKerror)
+            return false;
+    }
+
+    return !errors;
+}
+
+/****************************
+ * Do byte or word alignment as necessary.
+ * Align sizes of 0, as we may not know array sizes yet.
+ *
+ * alignment: struct alignment that is in effect
+ * size: alignment requirement of field
+ */
+
+void AggregateDeclaration::alignmember(
+        structalign_t alignment,
+        unsigned size,
+        unsigned *poffset)
+{
+    //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset);
+    switch (alignment)
+    {
+        case (structalign_t) 1:
+            // No alignment
+            break;
+
+        case (structalign_t) STRUCTALIGN_DEFAULT:
+            // Alignment in Target::fieldalignsize must match what the
+            // corresponding C compiler's default alignment behavior is.
+            assert(size > 0 && !(size & (size - 1)));
+            *poffset = (*poffset + size - 1) & ~(size - 1);
+            break;
+
+        default:
+            // Align on alignment boundary, which must be a positive power of 2
+            assert(alignment > 0 && !(alignment & (alignment - 1)));
+            *poffset = (*poffset + alignment - 1) & ~(alignment - 1);
+            break;
+    }
+}
+
+/****************************************
+ * Place a member (mem) into an aggregate (agg), which can be a struct, union or class
+ * Returns:
+ *      offset to place field at
+ *
+ * nextoffset:    next location in aggregate
+ * memsize:       size of member
+ * memalignsize:  size of member for alignment purposes
+ * alignment:     alignment in effect for this member
+ * paggsize:      size of aggregate (updated)
+ * paggalignsize: size of aggregate for alignment purposes (updated)
+ * isunion:       the aggregate is a union
+ */
+unsigned AggregateDeclaration::placeField(
+        unsigned *nextoffset,
+        unsigned memsize,
+        unsigned memalignsize,
+        structalign_t alignment,
+        unsigned *paggsize,
+        unsigned *paggalignsize,
+        bool isunion
+        )
+{
+    unsigned ofs = *nextoffset;
+    alignmember(alignment, memalignsize, &ofs);
+    unsigned memoffset = ofs;
+    ofs += memsize;
+    if (ofs > *paggsize)
+        *paggsize = ofs;
+    if (!isunion)
+        *nextoffset = ofs;
+
+    if (alignment != STRUCTALIGN_DEFAULT)
+    {
+        if (memalignsize < alignment)
+            memalignsize = alignment;
+    }
+
+    if (*paggalignsize < memalignsize)
+        *paggalignsize = memalignsize;
+
+    return memoffset;
+}
+
+
+/****************************************
+ * Returns true if there's an extra member which is the 'this'
+ * pointer to the enclosing context (enclosing aggregate or function)
+ */
+
+bool AggregateDeclaration::isNested()
+{
+    return enclosing != NULL;
+}
+
+/* Append vthis field (this->tupleof[$-1]) to make this aggregate type nested.
+ */
+void AggregateDeclaration::makeNested()
+{
+    if (enclosing)  // if already nested
+        return;
+    if (sizeok == SIZEOKdone)
+        return;
+    if (isUnionDeclaration() || isInterfaceDeclaration())
+        return;
+    if (storage_class & STCstatic)
+        return;
+
+    // If nested struct, add in hidden 'this' pointer to outer scope
+    Dsymbol *s = toParent2();
+    if (!s)
+        return;
+    Type *t = NULL;
+    if (FuncDeclaration *fd = s->isFuncDeclaration())
+    {
+        enclosing = fd;
+
+        /* Bugzilla 14422: If a nested class parent is a function, its
+         * context pointer (== `outer`) should be void* always.
+         */
+        t = Type::tvoidptr;
+    }
+    else if (AggregateDeclaration *ad = s->isAggregateDeclaration())
+    {
+        if (isClassDeclaration() && ad->isClassDeclaration())
+        {
+            enclosing = ad;
+        }
+        else if (isStructDeclaration())
+        {
+            if (TemplateInstance *ti = ad->parent->isTemplateInstance())
+            {
+                enclosing = ti->enclosing;
+            }
+        }
+
+        t = ad->handleType();
+    }
+    if (enclosing)
+    {
+        //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing->toChars());
+        assert(t);
+        if (t->ty == Tstruct)
+            t = Type::tvoidptr;     // t should not be a ref type
+        assert(!vthis);
+        vthis = new ThisDeclaration(loc, t);
+        //vthis->storage_class |= STCref;
+
+        // Emulate vthis->addMember()
+        members->push(vthis);
+
+        // Emulate vthis->semantic()
+        vthis->storage_class |= STCfield;
+        vthis->parent = this;
+        vthis->protection = Prot(PROTpublic);
+        vthis->alignment = t->alignment();
+        vthis->semanticRun = PASSsemanticdone;
+
+        if (sizeok == SIZEOKfwd)
+            fields.push(vthis);
+    }
+}
+
+/*******************************************
+ * Look for constructor declaration.
+ */
+Dsymbol *AggregateDeclaration::searchCtor()
+{
+    Dsymbol *s = search(Loc(), Id::ctor);
+    if (s)
+    {
+        if (!(s->isCtorDeclaration() ||
+              s->isTemplateDeclaration() ||
+              s->isOverloadSet()))
+        {
+            s->error("is not a constructor; identifiers starting with __ are reserved for the implementation");
+            errors = true;
+            s = NULL;
+        }
+    }
+    if (s && s->toParent() != this)
+        s = NULL; // search() looks through ancestor classes
+    if (s)
+    {
+        // Finish all constructors semantics to determine this->noDefaultCtor.
+        struct SearchCtor
+        {
+            static int fp(Dsymbol *s, void *ctxt)
+            {
+                CtorDeclaration *f = s->isCtorDeclaration();
+                if (f && f->semanticRun == PASSinit)
+                    f->semantic(NULL);
+                return 0;
+            }
+        };
+
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *sm = (*members)[i];
+            sm->apply(&SearchCtor::fp, NULL);
+        }
+    }
+    return s;
+}
+
+/********************************* StructDeclaration ****************************/
+
+StructDeclaration::StructDeclaration(Loc loc, Identifier *id, bool inObject)
+    : AggregateDeclaration(loc, id)
+{
+    zeroInit = 0;       // assume false until we do semantic processing
+    hasIdentityAssign = false;
+    hasIdentityEquals = false;
+    postblit = NULL;
+
+    xeq = NULL;
+    xcmp = NULL;
+    xhash = NULL;
+    alignment = 0;
+    ispod = ISPODfwd;
+    arg1type = NULL;
+    arg2type = NULL;
+    requestTypeInfo = false;
+
+    // For forward references
+    type = new TypeStruct(this);
+
+    if (inObject)
+    {
+        if (id == Id::ModuleInfo && !Module::moduleinfo)
+            Module::moduleinfo = this;
+    }
+}
+
+StructDeclaration *StructDeclaration::create(Loc loc, Identifier *id, bool inObject)
+{
+    return new StructDeclaration(loc, id, inObject);
+}
+
+Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s)
+{
+    StructDeclaration *sd =
+        s ? (StructDeclaration *)s
+          : new StructDeclaration(loc, ident, false);
+    return ScopeDsymbol::syntaxCopy(sd);
+}
+
+void StructDeclaration::semantic(Scope *sc)
+{
+    //printf("StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok);
+
+    //static int count; if (++count == 20) halt();
+
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    int errors = global.errors;
+
+    //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok);
+    Scope *scx = NULL;
+    if (_scope)
+    {
+        sc = _scope;
+        scx = _scope;            // save so we don't make redundant copies
+        _scope = NULL;
+    }
+
+    if (!parent)
+    {
+        assert(sc->parent && sc->func);
+        parent = sc->parent;
+    }
+    assert(parent && !isAnonymous());
+
+    if (this->errors)
+        type = Type::terror;
+    if (semanticRun == PASSinit)
+        type = type->addSTC(sc->stc | storage_class);
+    type = type->semantic(loc, sc);
+
+    if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this)
+    {
+        TemplateInstance *ti = ((TypeStruct *)type)->sym->isInstantiated();
+        if (ti && isError(ti))
+            ((TypeStruct *)type)->sym = this;
+    }
+
+    // Ungag errors when not speculative
+    Ungag ungag = ungagSpeculative();
+
+    if (semanticRun == PASSinit)
+    {
+        protection = sc->protection;
+
+        alignment = sc->alignment();
+
+        storage_class |= sc->stc;
+        if (storage_class & STCdeprecated)
+            isdeprecated = true;
+        if (storage_class & STCabstract)
+            error("structs, unions cannot be abstract");
+        userAttribDecl = sc->userAttribDecl;
+    }
+    else if (symtab && !scx)
+    {
+        return;
+    }
+    semanticRun = PASSsemantic;
+
+    if (!members)               // if opaque declaration
+    {
+        semanticRun = PASSsemanticdone;
+        return;
+    }
+    if (!symtab)
+    {
+        symtab = new DsymbolTable();
+
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars());
+            s->addMember(sc, this);
+        }
+    }
+
+    Scope *sc2 = newScope(sc);
+
+    /* Set scope so if there are forward references, we still might be able to
+     * resolve individual members like enums.
+     */
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        //printf("struct: setScope %s %s\n", s->kind(), s->toChars());
+        s->setScope(sc2);
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->importAll(sc2);
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->semantic(sc2);
+    }
+
+    if (!determineFields())
+    {
+        assert(type->ty == Terror);
+        sc2->pop();
+        semanticRun = PASSsemanticdone;
+        return;
+    }
+
+    /* Following special member functions creation needs semantic analysis
+     * completion of sub-structs in each field types. For example, buildDtor
+     * needs to check existence of elaborate dtor in type of each fields.
+     * See the case in compilable/test14838.d
+     */
+    for (size_t i = 0; i < fields.dim; i++)
+    {
+        VarDeclaration *v = fields[i];
+        Type *tb = v->type->baseElemOf();
+        if (tb->ty != Tstruct)
+            continue;
+        StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+        if (sd->semanticRun >= PASSsemanticdone)
+            continue;
+
+        sc2->pop();
+
+        _scope = scx ? scx : sc->copy();
+        _scope->setNoFree();
+        _scope->_module->addDeferredSemantic(this);
+
+        //printf("\tdeferring %s\n", toChars());
+        return;
+    }
+
+    /* Look for special member functions.
+     */
+    aggNew =       (NewDeclaration *)search(Loc(), Id::classNew);
+    aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete);
+
+    // Look for the constructor
+    ctor = searchCtor();
+
+    dtor = buildDtor(this, sc2);
+    postblit = buildPostBlit(this, sc2);
+
+    buildOpAssign(this, sc2);
+    buildOpEquals(this, sc2);
+
+    xeq = buildXopEquals(this, sc2);
+    xcmp = buildXopCmp(this, sc2);
+    xhash = buildXtoHash(this, sc2);
+
+    inv = buildInv(this, sc2);
+
+    Module::dprogress++;
+    semanticRun = PASSsemanticdone;
+    //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
+
+    sc2->pop();
+
+    if (ctor)
+    {
+        Dsymbol *scall = search(Loc(), Id::call);
+        if (scall)
+        {
+            unsigned xerrors = global.startGagging();
+            sc = sc->push();
+            sc->tinst = NULL;
+            sc->minst = NULL;
+            FuncDeclaration *fcall = resolveFuncCall(loc, sc, scall, NULL, NULL, NULL, 1);
+            sc = sc->pop();
+            global.endGagging(xerrors);
+
+            if (fcall && fcall->isStatic())
+            {
+                error(fcall->loc, "static opCall is hidden by constructors and can never be called");
+                errorSupplemental(fcall->loc, "Please use a factory method instead, or replace all constructors with static opCall.");
+            }
+        }
+    }
+
+    if (global.errors != errors)
+    {
+        // The type is no good.
+        type = Type::terror;
+        this->errors = true;
+        if (deferred)
+            deferred->errors = true;
+    }
+
+    if (deferred && !global.gag)
+    {
+        deferred->semantic2(sc);
+        deferred->semantic3(sc);
+    }
+
+#if 0
+    if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this)
+    {
+        printf("this = %p %s\n", this, this->toChars());
+        printf("type = %d sym = %p\n", type->ty, ((TypeStruct *)type)->sym);
+    }
+#endif
+    assert(type->ty != Tstruct || ((TypeStruct *)type)->sym == this);
+}
+
+Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
+
+    if (_scope && !symtab)
+        semantic(_scope);
+
+    if (!members || !symtab)    // opaque or semantic() is not yet called
+    {
+        error("is forward referenced when looking for '%s'", ident->toChars());
+        return NULL;
+    }
+
+    return ScopeDsymbol::search(loc, ident, flags);
+}
+
+void StructDeclaration::finalizeSize()
+{
+    //printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
+    assert(sizeok != SIZEOKdone);
+
+    //printf("+StructDeclaration::finalizeSize() %s, fields.dim = %d, sizeok = %d\n", toChars(), fields.dim, sizeok);
+
+    fields.setDim(0);   // workaround
+
+    // Set the offsets of the fields and determine the size of the struct
+    unsigned offset = 0;
+    bool isunion = isUnionDeclaration() != NULL;
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->setFieldOffset(this, &offset, isunion);
+    }
+    if (type->ty == Terror)
+        return;
+
+    // 0 sized struct's are set to 1 byte
+    if (structsize == 0)
+    {
+        structsize = 1;
+        alignsize = 1;
+    }
+
+    // Round struct size up to next alignsize boundary.
+    // This will ensure that arrays of structs will get their internals
+    // aligned properly.
+    if (alignment == STRUCTALIGN_DEFAULT)
+        structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
+    else
+        structsize = (structsize + alignment - 1) & ~(alignment - 1);
+
+    sizeok = SIZEOKdone;
+
+    //printf("-StructDeclaration::finalizeSize() %s, fields.dim = %d, structsize = %d\n", toChars(), fields.dim, structsize);
+
+    if (errors)
+        return;
+
+    // Calculate fields[i]->overlapped
+    if (checkOverlappedFields())
+    {
+        errors = true;
+        return;
+    }
+
+    // Determine if struct is all zeros or not
+    zeroInit = 1;
+    for (size_t i = 0; i < fields.dim; i++)
+    {
+        VarDeclaration *vd = fields[i];
+        if (vd->_init)
+        {
+            // Should examine init to see if it is really all 0's
+            zeroInit = 0;
+            break;
+        }
+        else if (!vd->type->isZeroInit(loc))
+        {
+            zeroInit = 0;
+            break;
+        }
+    }
+
+    TypeTuple *tt = toArgTypes(type);
+    size_t dim = tt->arguments->dim;
+    if (dim >= 1)
+    {
+        assert(dim <= 2);
+        arg1type = (*tt->arguments)[0]->type;
+        if (dim == 2)
+            arg2type = (*tt->arguments)[1]->type;
+    }
+}
+
+/***************************************
+ * Fit elements[] to the corresponding type of field[].
+ * Input:
+ *      loc
+ *      sc
+ *      elements    The explicit arguments that given to construct object.
+ *      stype       The constructed object type.
+ * Returns false if any errors occur.
+ * Otherwise, returns true and elements[] are rewritten for the output.
+ */
+bool StructDeclaration::fit(Loc loc, Scope *sc, Expressions *elements, Type *stype)
+{
+    if (!elements)
+        return true;
+
+    size_t nfields = fields.dim - isNested();
+    size_t offset = 0;
+    for (size_t i = 0; i < elements->dim; i++)
+    {
+        Expression *e = (*elements)[i];
+        if (!e)
+            continue;
+
+        e = resolveProperties(sc, e);
+        if (i >= nfields)
+        {
+            if (i == fields.dim - 1 && isNested() && e->op == TOKnull)
+            {
+                // CTFE sometimes creates null as hidden pointer; we'll allow this.
+                continue;
+            }
+            ::error(loc, "more initializers than fields (%d) of %s", nfields, toChars());
+            return false;
+        }
+        VarDeclaration *v = fields[i];
+        if (v->offset < offset)
+        {
+            ::error(loc, "overlapping initialization for %s", v->toChars());
+            return false;
+        }
+        offset = (unsigned)(v->offset + v->type->size());
+
+        Type *t = v->type;
+        if (stype)
+            t = t->addMod(stype->mod);
+        Type *origType = t;
+        Type *tb = t->toBasetype();
+
+        /* Look for case of initializing a static array with a too-short
+         * string literal, such as:
+         *  char[5] foo = "abc";
+         * Allow this by doing an explicit cast, which will lengthen the string
+         * literal.
+         */
+        if (e->op == TOKstring && tb->ty == Tsarray)
+        {
+            StringExp *se = (StringExp *)e;
+            Type *typeb = se->type->toBasetype();
+            TY tynto = tb->nextOf()->ty;
+            if (!se->committed &&
+                (typeb->ty == Tarray || typeb->ty == Tsarray) &&
+                (tynto == Tchar || tynto == Twchar || tynto == Tdchar) &&
+                se->numberOfCodeUnits(tynto) < ((TypeSArray *)tb)->dim->toInteger())
+            {
+                e = se->castTo(sc, t);
+                goto L1;
+            }
+        }
+
+        while (!e->implicitConvTo(t) && tb->ty == Tsarray)
+        {
+            /* Static array initialization, as in:
+             *  T[3][5] = e;
+             */
+            t = tb->nextOf();
+            tb = t->toBasetype();
+        }
+        if (!e->implicitConvTo(t))
+            t = origType;  // restore type for better diagnostic
+
+        e = e->implicitCastTo(sc, t);
+    L1:
+        if (e->op == TOKerror)
+            return false;
+
+        (*elements)[i] = doCopyOrMove(sc, e);
+    }
+    return true;
+}
+
+/***************************************
+ * Return true if struct is POD (Plain Old Data).
+ * This is defined as:
+ *      not nested
+ *      no postblits, destructors, or assignment operators
+ *      no 'ref' fields or fields that are themselves non-POD
+ * The idea being these are compatible with C structs.
+ */
+bool StructDeclaration::isPOD()
+{
+    // If we've already determined whether this struct is POD.
+    if (ispod != ISPODfwd)
+        return (ispod == ISPODyes);
+
+    ispod = ISPODyes;
+
+    if (enclosing || postblit || dtor)
+        ispod = ISPODno;
+
+    // Recursively check all fields are POD.
+    for (size_t i = 0; i < fields.dim; i++)
+    {
+        VarDeclaration *v = fields[i];
+        if (v->storage_class & STCref)
+        {
+            ispod = ISPODno;
+            break;
+        }
+
+        Type *tv = v->type->baseElemOf();
+        if (tv->ty == Tstruct)
+        {
+            TypeStruct *ts = (TypeStruct *)tv;
+            StructDeclaration *sd = ts->sym;
+            if (!sd->isPOD())
+            {
+                ispod = ISPODno;
+                break;
+            }
+        }
+    }
+
+    return (ispod == ISPODyes);
+}
+
+const char *StructDeclaration::kind()
+{
+    return "struct";
+}
+
+/********************************* UnionDeclaration ****************************/
+
+UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id)
+    : StructDeclaration(loc, id, false)
+{
+}
+
+Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    UnionDeclaration *ud = new UnionDeclaration(loc, ident);
+    return StructDeclaration::syntaxCopy(ud);
+}
+
+const char *UnionDeclaration::kind()
+{
+    return "union";
+}
diff --git a/gcc/d/dfrontend/dsymbol.c b/gcc/d/dfrontend/dsymbol.c
new file mode 100644
index 00000000000..aad13f4a59b
--- /dev/null
+++ b/gcc/d/dfrontend/dsymbol.c
@@ -0,0 +1,1796 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/dsymbol.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <limits.h>
+
+#include "rmem.h"
+#include "speller.h"
+#include "aav.h"
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "aggregate.h"
+#include "identifier.h"
+#include "module.h"
+#include "mtype.h"
+#include "expression.h"
+#include "statement.h"
+#include "declaration.h"
+#include "id.h"
+#include "scope.h"
+#include "init.h"
+#include "import.h"
+#include "template.h"
+#include "attrib.h"
+#include "enum.h"
+#include "lexer.h"
+
+bool symbolIsVisible(Dsymbol *origin, Dsymbol *s);
+typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s);
+int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL);
+Expression *semantic(Expression *e, Scope *sc);
+
+
+/****************************** Dsymbol ******************************/
+
+Dsymbol::Dsymbol()
+{
+    //printf("Dsymbol::Dsymbol(%p)\n", this);
+    this->ident = NULL;
+    this->parent = NULL;
+    this->csym = NULL;
+    this->isym = NULL;
+    this->loc = Loc();
+    this->comment = NULL;
+    this->_scope = NULL;
+    this->prettystring = NULL;
+    this->semanticRun = PASSinit;
+    this->errors = false;
+    this->depdecl = NULL;
+    this->userAttribDecl = NULL;
+    this->ddocUnittest = NULL;
+}
+
+Dsymbol::Dsymbol(Identifier *ident)
+{
+    //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
+    this->ident = ident;
+    this->parent = NULL;
+    this->csym = NULL;
+    this->isym = NULL;
+    this->loc = Loc();
+    this->comment = NULL;
+    this->_scope = NULL;
+    this->prettystring = NULL;
+    this->semanticRun = PASSinit;
+    this->errors = false;
+    this->depdecl = NULL;
+    this->userAttribDecl = NULL;
+    this->ddocUnittest = NULL;
+}
+
+Dsymbol *Dsymbol::create(Identifier *ident)
+{
+    return new Dsymbol(ident);
+}
+
+bool Dsymbol::equals(RootObject *o)
+{
+    if (this == o)
+        return true;
+    Dsymbol *s = (Dsymbol *)(o);
+    // Overload sets don't have an ident
+    if (s && ident && s->ident && ident->equals(s->ident))
+        return true;
+    return false;
+}
+
+/**************************************
+ * Copy the syntax.
+ * Used for template instantiations.
+ * If s is NULL, allocate the new object, otherwise fill it in.
+ */
+
+Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s)
+{
+    print();
+    printf("%s %s\n", kind(), toChars());
+    assert(0);
+    return NULL;
+}
+
+/**************************************
+ * Determine if this symbol is only one.
+ * Returns:
+ *      false, *ps = NULL: There are 2 or more symbols
+ *      true,  *ps = NULL: There are zero symbols
+ *      true,  *ps = symbol: The one and only one symbol
+ */
+
+bool Dsymbol::oneMember(Dsymbol **ps, Identifier *ident)
+{
+    //printf("Dsymbol::oneMember()\n");
+    *ps = this;
+    return true;
+}
+
+/*****************************************
+ * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
+ */
+
+bool Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident)
+{
+    //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0);
+    Dsymbol *s = NULL;
+
+    if (members)
+    {
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *sx = (*members)[i];
+            bool x = sx->oneMember(ps, ident);
+            //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps);
+            if (!x)
+            {
+                //printf("\tfalse 1\n");
+                assert(*ps == NULL);
+                return false;
+            }
+            if (*ps)
+            {
+                assert(ident);
+                if (!(*ps)->ident || !(*ps)->ident->equals(ident))
+                    continue;
+                if (!s)
+                    s = *ps;
+                else if (s->isOverloadable() && (*ps)->isOverloadable())
+                {
+                    // keep head of overload set
+                    FuncDeclaration *f1 = s->isFuncDeclaration();
+                    FuncDeclaration *f2 = (*ps)->isFuncDeclaration();
+                    if (f1 && f2)
+                    {
+                        assert(!f1->isFuncAliasDeclaration());
+                        assert(!f2->isFuncAliasDeclaration());
+                        for (; f1 != f2; f1 = f1->overnext0)
+                        {
+                            if (f1->overnext0 == NULL)
+                            {
+                                f1->overnext0 = f2;
+                                break;
+                            }
+                        }
+                    }
+                }
+                else                    // more than one symbol
+                {
+                    *ps = NULL;
+                    //printf("\tfalse 2\n");
+                    return false;
+                }
+            }
+        }
+    }
+    *ps = s;            // s is the one symbol, NULL if none
+    //printf("\ttrue\n");
+    return true;
+}
+
+/*****************************************
+ * Is Dsymbol a variable that contains pointers?
+ */
+
+bool Dsymbol::hasPointers()
+{
+    //printf("Dsymbol::hasPointers() %s\n", toChars());
+    return false;
+}
+
+bool Dsymbol::hasStaticCtorOrDtor()
+{
+    //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
+    return false;
+}
+
+void Dsymbol::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
+{
+}
+
+Identifier *Dsymbol::getIdent()
+{
+    return ident;
+}
+
+const char *Dsymbol::toChars()
+{
+    return ident ? ident->toChars() : (char *)"__anonymous";
+}
+
+const char *Dsymbol::toPrettyCharsHelper()
+{
+    return toChars();
+}
+
+const char *Dsymbol::toPrettyChars(bool QualifyTypes)
+{
+    if (prettystring && !QualifyTypes)
+        return (char *)prettystring;
+
+    //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
+    if (!parent)
+    {
+        const char *s = toChars();
+        if (!QualifyTypes)
+            prettystring = (utf8_t *)s;
+        return s;
+    }
+
+    // Computer number of components
+    size_t complength = 0;
+    for (Dsymbol *p = this; p; p = p->parent)
+        ++complength;
+
+    // Allocate temporary array comp[]
+    const char **comp = (const char **)malloc(complength * sizeof(char**));
+    if (!comp)
+        Mem::error();
+
+    // Fill in comp[] and compute length of final result
+    size_t length = 0;
+    int i = 0;
+    for (Dsymbol *p = this; p; p = p->parent)
+    {
+        const char *s = QualifyTypes ? p->toPrettyCharsHelper() : p->toChars();
+        const size_t len = strlen(s);
+        comp[i] = s;
+        ++i;
+        length += len + 1;
+    }
+
+    char *s = (char *)mem.xmalloc(length);
+    char *q = s + length - 1;
+    *q = 0;
+    for (size_t j = 0; j < complength; j++)
+    {
+        const char *t = comp[j];
+        const size_t len = strlen(t);
+        q -= len;
+        memcpy(q, t, len);
+        if (q == s)
+            break;
+        *--q = '.';
+    }
+    free(comp);
+    if (!QualifyTypes)
+        prettystring = (utf8_t *)s;
+    return s;
+}
+
+Loc& Dsymbol::getLoc()
+{
+    if (!loc.filename)  // avoid bug 5861.
+    {
+        Module *m = getModule();
+
+        if (m && m->srcfile)
+            loc.filename = m->srcfile->toChars();
+    }
+    return loc;
+}
+
+const char *Dsymbol::locToChars()
+{
+    return getLoc().toChars();
+}
+
+const char *Dsymbol::kind()
+{
+    return "symbol";
+}
+
+/*********************************
+ * If this symbol is really an alias for another,
+ * return that other.
+ * If needed, semantic() is invoked due to resolve forward reference.
+ */
+Dsymbol *Dsymbol::toAlias()
+{
+    return this;
+}
+
+/*********************************
+ * Resolve recursive tuple expansion in eponymous template.
+ */
+Dsymbol *Dsymbol::toAlias2()
+{
+    return toAlias();
+}
+
+Dsymbol *Dsymbol::pastMixin()
+{
+    Dsymbol *s = this;
+
+    //printf("Dsymbol::pastMixin() %s\n", toChars());
+    while (s && s->isTemplateMixin())
+        s = s->parent;
+    return s;
+}
+
+/**********************************
+ * `parent` field returns a lexically enclosing scope symbol this is a member of.
+ *
+ * `toParent()` returns a logically enclosing scope symbol this is a member of.
+ * It skips over TemplateMixin's.
+ *
+ * `toParent2()` returns an enclosing scope symbol this is living at runtime.
+ * It skips over both TemplateInstance's and TemplateMixin's.
+ * It's used when looking for the 'this' pointer of the enclosing function/class.
+ *
+ * Examples:
+ *  module mod;
+ *  template Foo(alias a) { mixin Bar!(); }
+ *  mixin template Bar() {
+ *    public {  // ProtDeclaration
+ *      void baz() { a = 2; }
+ *    }
+ *  }
+ *  void test() {
+ *    int v = 1;
+ *    alias foo = Foo!(v);
+ *    foo.baz();
+ *    assert(v == 2);
+ *  }
+ *
+ *  // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()')
+ *  // s.parent == TemplateMixin('mod.test.Foo!().Bar!()')
+ *  // s.toParent() == TemplateInstance('mod.test.Foo!()')
+ *  // s.toParent2() == FuncDeclaration('mod.test')
+ */
+Dsymbol *Dsymbol::toParent()
+{
+    return parent ? parent->pastMixin() : NULL;
+}
+
+/// ditto
+Dsymbol *Dsymbol::toParent2()
+{
+    Dsymbol *s = parent;
+    while (s && s->isTemplateInstance())
+        s = s->parent;
+    return s;
+}
+
+TemplateInstance *Dsymbol::isInstantiated()
+{
+    for (Dsymbol *s = parent; s; s = s->parent)
+    {
+        TemplateInstance *ti = s->isTemplateInstance();
+        if (ti && !ti->isTemplateMixin())
+            return ti;
+    }
+    return NULL;
+}
+
+// Check if this function is a member of a template which has only been
+// instantiated speculatively, eg from inside is(typeof()).
+// Return the speculative template instance it is part of,
+// or NULL if not speculative.
+TemplateInstance *Dsymbol::isSpeculative()
+{
+    Dsymbol *par = parent;
+    while (par)
+    {
+        TemplateInstance *ti = par->isTemplateInstance();
+        if (ti && ti->gagged)
+            return ti;
+        par = par->toParent();
+    }
+    return NULL;
+}
+
+Ungag Dsymbol::ungagSpeculative()
+{
+    unsigned oldgag = global.gag;
+
+    if (global.gag && !isSpeculative() && !toParent2()->isFuncDeclaration())
+        global.gag = 0;
+
+    return Ungag(oldgag);
+}
+
+bool Dsymbol::isAnonymous()
+{
+    return ident == NULL;
+}
+
+/*************************************
+ * Set scope for future semantic analysis so we can
+ * deal better with forward references.
+ */
+
+void Dsymbol::setScope(Scope *sc)
+{
+    //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc->stc);
+    if (!sc->nofree)
+        sc->setNoFree();                // may need it even after semantic() finishes
+    _scope = sc;
+    if (sc->depdecl)
+        depdecl = sc->depdecl;
+
+    if (!userAttribDecl)
+        userAttribDecl = sc->userAttribDecl;
+}
+
+void Dsymbol::importAll(Scope *sc)
+{
+}
+
+/*************************************
+ * Does semantic analysis on the public face of declarations.
+ */
+
+void Dsymbol::semantic(Scope *sc)
+{
+    error("%p has no semantic routine", this);
+}
+
+/*************************************
+ * Does semantic analysis on initializers and members of aggregates.
+ */
+
+void Dsymbol::semantic2(Scope *sc)
+{
+    // Most Dsymbols have no further semantic analysis needed
+}
+
+/*************************************
+ * Does semantic analysis on function bodies.
+ */
+
+void Dsymbol::semantic3(Scope *sc)
+{
+    // Most Dsymbols have no further semantic analysis needed
+}
+
+/*********************************************
+ * Search for ident as member of s.
+ * Params:
+ *  loc = location to print for error messages
+ *  ident = identifier to search for
+ *  flags = IgnoreXXXX
+ * Returns:
+ *  NULL if not found
+ */
+
+Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
+    return NULL;
+}
+
+/***************************************************
+ * Search for symbol with correct spelling.
+ */
+
+void *symbol_search_fp(void *arg, const char *seed, int *cost)
+{
+    /* If not in the lexer's string table, it certainly isn't in the symbol table.
+     * Doing this first is a lot faster.
+     */
+    size_t len = strlen(seed);
+    if (!len)
+        return NULL;
+    Identifier *id = Identifier::lookup(seed, len);
+    if (!id)
+        return NULL;
+
+    *cost = 0;
+    Dsymbol *s = (Dsymbol *)arg;
+    Module::clearCache();
+    return (void *)s->search(Loc(), id, IgnoreErrors);
+}
+
+Dsymbol *Dsymbol::search_correct(Identifier *ident)
+{
+    if (global.gag)
+        return NULL;            // don't do it for speculative compiles; too time consuming
+
+    return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, (void *)this, idchars);
+}
+
+/***************************************
+ * Search for identifier id as a member of 'this'.
+ * id may be a template instance.
+ * Returns:
+ *      symbol found, NULL if not
+ */
+Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id)
+{
+    //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
+    Dsymbol *s = toAlias();
+    Dsymbol *sm;
+
+    if (Declaration *d = s->isDeclaration())
+    {
+        if (d->inuse)
+        {
+            ::error(loc, "circular reference to '%s'", d->toPrettyChars());
+            return NULL;
+        }
+    }
+
+    switch (id->dyncast())
+    {
+        case DYNCAST_IDENTIFIER:
+            sm = s->search(loc, (Identifier *)id);
+            break;
+
+        case DYNCAST_DSYMBOL:
+        {
+            // It's a template instance
+            //printf("\ttemplate instance id\n");
+            Dsymbol *st = (Dsymbol *)id;
+            TemplateInstance *ti = st->isTemplateInstance();
+            sm = s->search(loc, ti->name);
+            if (!sm)
+            {
+                sm = s->search_correct(ti->name);
+                if (sm)
+                    ::error(loc, "template identifier '%s' is not a member of %s '%s', did you mean %s '%s'?",
+                          ti->name->toChars(), s->kind(), s->toPrettyChars(), sm->kind(), sm->toChars());
+                else
+                    ::error(loc, "template identifier '%s' is not a member of %s '%s'",
+                          ti->name->toChars(), s->kind(), s->toPrettyChars());
+                return NULL;
+            }
+            sm = sm->toAlias();
+            TemplateDeclaration *td = sm->isTemplateDeclaration();
+            if (!td)
+            {
+                ::error(loc, "%s.%s is not a template, it is a %s", s->toPrettyChars(), ti->name->toChars(), sm->kind());
+                return NULL;
+            }
+            ti->tempdecl = td;
+            if (!ti->semanticRun)
+                ti->semantic(sc);
+            sm = ti->toAlias();
+            break;
+        }
+
+        case DYNCAST_TYPE:
+        case DYNCAST_EXPRESSION:
+        default:
+            assert(0);
+    }
+    return sm;
+}
+
+bool Dsymbol::overloadInsert(Dsymbol *s)
+{
+    //printf("Dsymbol::overloadInsert('%s')\n", s->toChars());
+    return false;
+}
+
+d_uns64 Dsymbol::size(Loc loc)
+{
+    error("Dsymbol '%s' has no size", toChars());
+    return SIZE_INVALID;
+}
+
+bool Dsymbol::isforwardRef()
+{
+    return false;
+}
+
+AggregateDeclaration *Dsymbol::isThis()
+{
+    return NULL;
+}
+
+bool Dsymbol::isExport()
+{
+    return false;
+}
+
+bool Dsymbol::isImportedSymbol()
+{
+    return false;
+}
+
+bool Dsymbol::isDeprecated()
+{
+    return false;
+}
+
+bool Dsymbol::isOverloadable()
+{
+    return false;
+}
+
+LabelDsymbol *Dsymbol::isLabel()                // is this a LabelDsymbol()?
+{
+    return NULL;
+}
+
+/// Returns an AggregateDeclaration when toParent() is that.
+AggregateDeclaration *Dsymbol::isMember()
+{
+    //printf("Dsymbol::isMember() %s\n", toChars());
+    Dsymbol *parent = toParent();
+    //printf("parent is %s %s\n", parent->kind(), parent->toChars());
+    return parent ? parent->isAggregateDeclaration() : NULL;
+}
+
+/// Returns an AggregateDeclaration when toParent2() is that.
+AggregateDeclaration *Dsymbol::isMember2()
+{
+    //printf("Dsymbol::isMember2() %s\n", toChars());
+    Dsymbol *parent = toParent2();
+    //printf("parent is %s %s\n", parent->kind(), parent->toChars());
+    return parent ? parent->isAggregateDeclaration() : NULL;
+}
+
+// is this a member of a ClassDeclaration?
+ClassDeclaration *Dsymbol::isClassMember()
+{
+    AggregateDeclaration *ad = isMember();
+    return ad ? ad->isClassDeclaration() : NULL;
+}
+
+Type *Dsymbol::getType()
+{
+    return NULL;
+}
+
+bool Dsymbol::needThis()
+{
+    return false;
+}
+
+/*********************************
+ * Iterate this dsymbol or members of this scoped dsymbol, then
+ * call `fp` with the found symbol and `param`.
+ * Params:
+ *  fp = function pointer to process the iterated symbol.
+ *       If it returns nonzero, the iteration will be aborted.
+ *  param = a parameter passed to fp.
+ * Returns:
+ *  nonzero if the iteration is aborted by the return value of fp,
+ *  or 0 if it's completed.
+ */
+int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param)
+{
+    return (*fp)(this, param);
+}
+
+void Dsymbol::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+    //printf("Dsymbol::addMember('%s')\n", toChars());
+    //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds->toChars());
+    //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds->symtab = %p)\n", this, toChars(), sds, sds->symtab);
+    parent = sds;
+    if (!isAnonymous())         // no name, so can't add it to symbol table
+    {
+        if (!sds->symtabInsert(this))    // if name is already defined
+        {
+            Dsymbol *s2 = sds->symtab->lookup(ident);
+            if (!s2->overloadInsert(this))
+            {
+                sds->multiplyDefined(Loc(), this, s2);
+                errors = true;
+            }
+        }
+        if (sds->isAggregateDeclaration() || sds->isEnumDeclaration())
+        {
+            if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::_mangleof)
+            {
+                error(".%s property cannot be redefined", ident->toChars());
+                errors = true;
+            }
+        }
+    }
+}
+
+void Dsymbol::error(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::verror(getLoc(), format, ap, kind(), toPrettyChars());
+    va_end(ap);
+}
+
+void Dsymbol::error(Loc loc, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::verror(loc, format, ap, kind(), toPrettyChars());
+    va_end(ap);
+}
+
+void Dsymbol::deprecation(Loc loc, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::vdeprecation(loc, format, ap, kind(), toPrettyChars());
+    va_end(ap);
+}
+
+void Dsymbol::deprecation(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::vdeprecation(getLoc(), format, ap, kind(), toPrettyChars());
+    va_end(ap);
+}
+
+void Dsymbol::checkDeprecated(Loc loc, Scope *sc)
+{
+    if (global.params.useDeprecated != 1 && isDeprecated())
+    {
+        // Don't complain if we're inside a deprecated symbol's scope
+        for (Dsymbol *sp = sc->parent; sp; sp = sp->parent)
+        {
+            if (sp->isDeprecated())
+                goto L1;
+        }
+
+        for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing)
+        {
+            if (sc2->scopesym && sc2->scopesym->isDeprecated())
+                goto L1;
+
+            // If inside a StorageClassDeclaration that is deprecated
+            if (sc2->stc & STCdeprecated)
+                goto L1;
+        }
+
+        const char *message = NULL;
+        for (Dsymbol *p = this; p; p = p->parent)
+        {
+            message = p->depdecl ? p->depdecl->getMessage() : NULL;
+            if (message)
+                break;
+        }
+
+        if (message)
+            deprecation(loc, "is deprecated - %s", message);
+        else
+            deprecation(loc, "is deprecated");
+    }
+
+  L1:
+    Declaration *d = isDeclaration();
+    if (d && d->storage_class & STCdisable)
+    {
+        if (!(sc->func && sc->func->storage_class & STCdisable))
+        {
+            if (d->toParent() && d->isPostBlitDeclaration())
+                d->toParent()->error(loc, "is not copyable because it is annotated with @disable");
+            else
+                error(loc, "is not callable because it is annotated with @disable");
+        }
+    }
+}
+
+/**********************************
+ * Determine which Module a Dsymbol is in.
+ */
+
+Module *Dsymbol::getModule()
+{
+    //printf("Dsymbol::getModule()\n");
+    if (TemplateInstance *ti = isInstantiated())
+        return ti->tempdecl->getModule();
+
+    Dsymbol *s = this;
+    while (s)
+    {
+        //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars());
+        Module *m = s->isModule();
+        if (m)
+            return m;
+        s = s->parent;
+    }
+    return NULL;
+}
+
+/**********************************
+ * Determine which Module a Dsymbol is in, as far as access rights go.
+ */
+
+Module *Dsymbol::getAccessModule()
+{
+    //printf("Dsymbol::getAccessModule()\n");
+    if (TemplateInstance *ti = isInstantiated())
+        return ti->tempdecl->getAccessModule();
+
+    Dsymbol *s = this;
+    while (s)
+    {
+        //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars());
+        Module *m = s->isModule();
+        if (m)
+            return m;
+        TemplateInstance *ti = s->isTemplateInstance();
+        if (ti && ti->enclosing)
+        {
+            /* Because of local template instantiation, the parent isn't where the access
+             * rights come from - it's the template declaration
+             */
+            s = ti->tempdecl;
+        }
+        else
+            s = s->parent;
+    }
+    return NULL;
+}
+
+/*************************************
+ */
+
+Prot Dsymbol::prot()
+{
+    return Prot(PROTpublic);
+}
+
+/*************************************
+ * Do syntax copy of an array of Dsymbol's.
+ */
+
+Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a)
+{
+
+    Dsymbols *b = NULL;
+    if (a)
+    {
+        b = a->copy();
+        for (size_t i = 0; i < b->dim; i++)
+        {
+            (*b)[i] = (*b)[i]->syntaxCopy(NULL);
+        }
+    }
+    return b;
+}
+
+/****************************************
+ * Add documentation comment to Dsymbol.
+ * Ignore NULL comments.
+ */
+
+void Dsymbol::addComment(const utf8_t *comment)
+{
+    //if (comment)
+        //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
+
+    if (!this->comment)
+        this->comment = comment;
+    else if (comment && strcmp((char *)comment, (char *)this->comment) != 0)
+    {   // Concatenate the two
+        this->comment = Lexer::combineComments(this->comment, comment);
+    }
+}
+
+/****************************************
+ * Returns true if this symbol is defined in a non-root module without instantiation.
+ */
+bool Dsymbol::inNonRoot()
+{
+    Dsymbol *s = parent;
+    for (; s; s = s->toParent())
+    {
+        if (TemplateInstance *ti = s->isTemplateInstance())
+        {
+            return false;
+        }
+        if (Module *m = s->isModule())
+        {
+            if (!m->isRoot())
+                return true;
+            break;
+        }
+    }
+    return false;
+}
+
+/********************************* OverloadSet ****************************/
+
+OverloadSet::OverloadSet(Identifier *ident, OverloadSet *os)
+    : Dsymbol(ident)
+{
+    if (os)
+    {
+        for (size_t i = 0; i < os->a.dim; i++)
+        {
+            a.push(os->a[i]);
+        }
+    }
+}
+
+void OverloadSet::push(Dsymbol *s)
+{
+    a.push(s);
+}
+
+const char *OverloadSet::kind()
+{
+    return "overloadset";
+}
+
+
+/********************************* ScopeDsymbol ****************************/
+
+ScopeDsymbol::ScopeDsymbol()
+    : Dsymbol()
+{
+    members = NULL;
+    symtab = NULL;
+    endlinnum = 0;
+    importedScopes = NULL;
+    prots = NULL;
+}
+
+ScopeDsymbol::ScopeDsymbol(Identifier *id)
+    : Dsymbol(id)
+{
+    members = NULL;
+    symtab = NULL;
+    endlinnum = 0;
+    importedScopes = NULL;
+    prots = NULL;
+}
+
+Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s)
+{
+    //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
+    ScopeDsymbol *sds = s ? (ScopeDsymbol *)s : new ScopeDsymbol(ident);
+    sds->members = arraySyntaxCopy(members);
+    sds->endlinnum = endlinnum;
+    return sds;
+}
+
+/*****************************************
+ * This function is #1 on the list of functions that eat cpu time.
+ * Be very, very careful about slowing it down.
+ */
+
+Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
+    //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0;
+
+    // Look in symbols declared in this module
+    if (symtab && !(flags & SearchImportsOnly))
+    {
+        //printf(" look in locals\n");
+        Dsymbol *s1 = symtab->lookup(ident);
+        if (s1)
+        {
+            //printf("\tfound in locals = '%s.%s'\n",toChars(),s1->toChars());
+            return s1;
+        }
+    }
+    //printf(" not found in locals\n");
+
+    // Look in imported scopes
+    if (importedScopes)
+    {
+        //printf(" look in imports\n");
+        Dsymbol *s = NULL;
+        OverloadSet *a = NULL;
+
+        // Look in imported modules
+        for (size_t i = 0; i < importedScopes->dim; i++)
+        {
+            // If private import, don't search it
+            if ((flags & IgnorePrivateImports) && prots[i] == PROTprivate)
+                continue;
+
+            int sflags = flags & (IgnoreErrors | IgnoreAmbiguous | IgnoreSymbolVisibility); // remember these in recursive searches
+            Dsymbol *ss = (*importedScopes)[i];
+
+            //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport());
+
+            if (ss->isModule())
+            {
+                if (flags & SearchLocalsOnly)
+                    continue;
+            }
+            else // mixin template
+            {
+                if (flags & SearchImportsOnly)
+                    continue;
+                // compatibility with -transition=import (Bugzilla 15925)
+                // SearchLocalsOnly should always get set for new lookup rules
+                sflags |= (flags & SearchLocalsOnly);
+            }
+
+            /* Don't find private members if ss is a module
+             */
+            Dsymbol *s2 = ss->search(loc, ident, sflags | (ss->isModule() ? IgnorePrivateImports : IgnoreNone));
+            if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2))
+                continue;
+            if (!s)
+            {
+                s = s2;
+                if (s && s->isOverloadSet())
+                    a = mergeOverloadSet(ident, a, s);
+            }
+            else if (s2 && s != s2)
+            {
+                if (s->toAlias() == s2->toAlias() ||
+                    s->getType() == s2->getType() && s->getType())
+                {
+                    /* After following aliases, we found the same
+                     * symbol, so it's not an ambiguity.  But if one
+                     * alias is deprecated or less accessible, prefer
+                     * the other.
+                     */
+                    if (s->isDeprecated() ||
+                        s->prot().isMoreRestrictiveThan(s2->prot()) && s2->prot().kind != PROTnone)
+                        s = s2;
+                }
+                else
+                {
+                    /* Two imports of the same module should be regarded as
+                     * the same.
+                     */
+                    Import *i1 = s->isImport();
+                    Import *i2 = s2->isImport();
+                    if (!(i1 && i2 &&
+                          (i1->mod == i2->mod ||
+                           (!i1->parent->isImport() && !i2->parent->isImport() &&
+                            i1->ident->equals(i2->ident))
+                          )
+                         )
+                       )
+                    {
+                        /* Bugzilla 8668:
+                         * Public selective import adds AliasDeclaration in module.
+                         * To make an overload set, resolve aliases in here and
+                         * get actual overload roots which accessible via s and s2.
+                         */
+                        s = s->toAlias();
+                        s2 = s2->toAlias();
+
+                        /* If both s2 and s are overloadable (though we only
+                         * need to check s once)
+                         */
+                        if ((s2->isOverloadSet() || s2->isOverloadable()) &&
+                            (a || s->isOverloadable()))
+                        {
+                            a = mergeOverloadSet(ident, a, s2);
+                            continue;
+                        }
+                        if (flags & IgnoreAmbiguous)    // if return NULL on ambiguity
+                            return NULL;
+                        if (!(flags & IgnoreErrors))
+                            ScopeDsymbol::multiplyDefined(loc, s, s2);
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (s)
+        {
+            /* Build special symbol if we had multiple finds
+             */
+            if (a)
+            {
+                if (!s->isOverloadSet())
+                    a = mergeOverloadSet(ident, a, s);
+                s = a;
+            }
+
+            // TODO: remove once private symbol visibility has been deprecated
+            if (!(flags & IgnoreErrors) && s->prot().kind == PROTprivate &&
+                !s->isOverloadable() && !s->parent->isTemplateMixin() && !s->parent->isNspace())
+            {
+                AliasDeclaration *ad;
+                // accessing private selective and renamed imports is
+                // deprecated by restricting the symbol visibility
+                if (s->isImport() || (ad = s->isAliasDeclaration()) != NULL && ad->_import != NULL)
+                {}
+                else
+                    error(loc, "%s %s is private", s->kind(), s->toPrettyChars());
+            }
+            //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
+            return s;
+        }
+        //printf(" not found in imports\n");
+    }
+
+    return NULL;
+}
+
+OverloadSet *ScopeDsymbol::mergeOverloadSet(Identifier *ident, OverloadSet *os, Dsymbol *s)
+{
+    if (!os)
+    {
+        os = new OverloadSet(ident);
+        os->parent = this;
+    }
+    if (OverloadSet *os2 = s->isOverloadSet())
+    {
+        // Merge the cross-module overload set 'os2' into 'os'
+        if (os->a.dim == 0)
+        {
+            os->a.setDim(os2->a.dim);
+            memcpy(os->a.tdata(), os2->a.tdata(), sizeof(os->a[0]) * os2->a.dim);
+        }
+        else
+        {
+            for (size_t i = 0; i < os2->a.dim; i++)
+            {
+                os = mergeOverloadSet(ident, os, os2->a[i]);
+            }
+        }
+    }
+    else
+    {
+        assert(s->isOverloadable());
+
+        /* Don't add to os[] if s is alias of previous sym
+         */
+        for (size_t j = 0; j < os->a.dim; j++)
+        {
+            Dsymbol *s2 = os->a[j];
+            if (s->toAlias() == s2->toAlias())
+            {
+                if (s2->isDeprecated() ||
+                    (s2->prot().isMoreRestrictiveThan(s->prot()) &&
+                     s->prot().kind != PROTnone))
+                {
+                    os->a[j] = s;
+                }
+                goto Lcontinue;
+            }
+        }
+        os->push(s);
+    Lcontinue:
+        ;
+    }
+    return os;
+}
+
+void ScopeDsymbol::importScope(Dsymbol *s, Prot protection)
+{
+    //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection);
+
+    // No circular or redundant import's
+    if (s != this)
+    {
+        if (!importedScopes)
+            importedScopes = new Dsymbols();
+        else
+        {
+            for (size_t i = 0; i < importedScopes->dim; i++)
+            {
+                Dsymbol *ss = (*importedScopes)[i];
+                if (ss == s)                    // if already imported
+                {
+                    if (protection.kind > prots[i])
+                        prots[i] = protection.kind;  // upgrade access
+                    return;
+                }
+            }
+        }
+        importedScopes->push(s);
+        prots = (PROTKIND *)mem.xrealloc(prots, importedScopes->dim * sizeof(prots[0]));
+        prots[importedScopes->dim - 1] = protection.kind;
+    }
+}
+
+static void bitArraySet(BitArray *array, size_t idx)
+{
+    array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] |= 1 << (idx & (sizeof(size_t) * CHAR_BIT - 1));
+}
+
+static bool bitArrayGet(BitArray *array, size_t idx)
+{
+    return (array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] & (1 << (idx & (sizeof(size_t) * CHAR_BIT - 1)))) != 0;
+}
+
+static void bitArrayLength(BitArray *array, size_t len)
+{
+    size_t obytes = (array->len + CHAR_BIT - 1) / CHAR_BIT;
+    size_t nbytes = (len + CHAR_BIT - 1) / CHAR_BIT;
+
+    if (obytes < nbytes)
+    {
+        if (!array->ptr)
+            array->ptr = (size_t *)mem.xmalloc(nbytes * sizeof(size_t));
+        else
+            array->ptr = (size_t *)mem.xrealloc(array->ptr, nbytes * sizeof(size_t));
+
+        for (size_t i = obytes; i < nbytes; i++)
+            array->ptr[i] = 0;
+    }
+    array->len = len;
+}
+
+void ScopeDsymbol::addAccessiblePackage(Package *p, Prot protection)
+{
+    BitArray *pary = protection.kind == PROTprivate ? &privateAccessiblePackages : &accessiblePackages;
+    if (pary->len <= p->tag)
+        bitArrayLength(pary, p->tag + 1);
+    bitArraySet(pary, p->tag);
+}
+
+bool ScopeDsymbol::isPackageAccessible(Package *p, Prot protection, int flags)
+{
+    if ((p->tag < accessiblePackages.len && bitArrayGet(&accessiblePackages, p->tag)) ||
+        (protection.kind == PROTprivate && p->tag < privateAccessiblePackages.len && bitArrayGet(&privateAccessiblePackages, p->tag)))
+        return true;
+    if (importedScopes)
+    {
+        for (size_t i = 0; i < importedScopes->dim; i++)
+        {
+            // only search visible scopes && imported modules should ignore private imports
+            Dsymbol *ss = (*importedScopes)[i];
+            if (protection.kind <= prots[i] &&
+                ss->isScopeDsymbol()->isPackageAccessible(p, protection, IgnorePrivateImports))
+                return true;
+        }
+    }
+    return false;
+}
+
+bool ScopeDsymbol::isforwardRef()
+{
+    return (members == NULL);
+}
+
+void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2)
+{
+#if 0
+    printf("ScopeDsymbol::multiplyDefined()\n");
+    printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1->toChars(), s1->kind(), s1->parent ? s1->parent->toChars() : "");
+    printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : "");
+#endif
+    if (loc.filename)
+    {   ::error(loc, "%s at %s conflicts with %s at %s",
+            s1->toPrettyChars(),
+            s1->locToChars(),
+            s2->toPrettyChars(),
+            s2->locToChars());
+    }
+    else
+    {
+        s1->error(s1->loc, "conflicts with %s %s at %s",
+            s2->kind(),
+            s2->toPrettyChars(),
+            s2->locToChars());
+    }
+}
+
+const char *ScopeDsymbol::kind()
+{
+    return "ScopeDsymbol";
+}
+
+Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s)
+{
+    return symtab->insert(s);
+}
+
+Dsymbol *ScopeDsymbol::symtabLookup(Dsymbol *s, Identifier *id)
+{
+    assert(0);
+}
+
+/****************************************
+ * Return true if any of the members are static ctors or static dtors, or if
+ * any members have members that are.
+ */
+
+bool ScopeDsymbol::hasStaticCtorOrDtor()
+{
+    if (members)
+    {
+        for (size_t i = 0; i < members->dim; i++)
+        {   Dsymbol *member = (*members)[i];
+
+            if (member->hasStaticCtorOrDtor())
+                return true;
+        }
+    }
+    return false;
+}
+
+/***************************************
+ * Determine number of Dsymbols, folding in AttribDeclaration members.
+ */
+
+static int dimDg(void *ctx, size_t n, Dsymbol *)
+{
+    ++*(size_t *)ctx;
+    return 0;
+}
+
+size_t ScopeDsymbol::dim(Dsymbols *members)
+{
+    size_t n = 0;
+    ScopeDsymbol_foreach(NULL, members, &dimDg, &n);
+    return n;
+}
+
+/***************************************
+ * Get nth Dsymbol, folding in AttribDeclaration members.
+ * Returns:
+ *      Dsymbol*        nth Dsymbol
+ *      NULL            not found, *pn gets incremented by the number
+ *                      of Dsymbols
+ */
+
+struct GetNthSymbolCtx
+{
+    size_t nth;
+    Dsymbol *sym;
+};
+
+static int getNthSymbolDg(void *ctx, size_t n, Dsymbol *sym)
+{
+    GetNthSymbolCtx *p = (GetNthSymbolCtx *)ctx;
+    if (n == p->nth)
+    {   p->sym = sym;
+        return 1;
+    }
+    return 0;
+}
+
+Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *pn)
+{
+    GetNthSymbolCtx ctx = { nth, NULL };
+    int res = ScopeDsymbol_foreach(NULL, members, &getNthSymbolDg, &ctx);
+    return res ? ctx.sym : NULL;
+}
+
+/***************************************
+ * Expands attribute declarations in members in depth first
+ * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each
+ * member.
+ * If dg returns !=0, stops and returns that value else returns 0.
+ * Use this function to avoid the O(N + N^2/2) complexity of
+ * calculating dim and calling N times getNth.
+ */
+
+int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn)
+{
+    assert(dg);
+    if (!members)
+        return 0;
+
+    size_t n = pn ? *pn : 0; // take over index
+    int result = 0;
+    for (size_t i = 0; i < members->dim; i++)
+    {   Dsymbol *s = (*members)[i];
+
+        if (AttribDeclaration *a = s->isAttribDeclaration())
+            result = ScopeDsymbol_foreach(sc, a->include(sc, NULL), dg, ctx, &n);
+        else if (TemplateMixin *tm = s->isTemplateMixin())
+            result = ScopeDsymbol_foreach(sc, tm->members, dg, ctx, &n);
+        else if (s->isTemplateInstance())
+            ;
+        else if (s->isUnitTestDeclaration())
+            ;
+        else
+            result = dg(ctx, n++, s);
+
+        if (result)
+            break;
+    }
+
+    if (pn)
+        *pn = n; // update index
+    return result;
+}
+
+/*******************************************
+ * Look for member of the form:
+ *      const(MemberInfo)[] getMembers(string);
+ * Returns NULL if not found
+ */
+
+FuncDeclaration *ScopeDsymbol::findGetMembers()
+{
+    Dsymbol *s = search_function(this, Id::getmembers);
+    FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
+
+#if 0  // Finish
+    static TypeFunction *tfgetmembers;
+
+    if (!tfgetmembers)
+    {
+        Scope sc;
+        Parameters *parameters = new Parameters;
+        Parameters *p = new Parameter(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL);
+        parameters->push(p);
+
+        Type *tret = NULL;
+        tfgetmembers = new TypeFunction(parameters, tret, 0, LINKd);
+        tfgetmembers = (TypeFunction *)tfgetmembers->semantic(Loc(), &sc);
+    }
+    if (fdx)
+        fdx = fdx->overloadExactMatch(tfgetmembers);
+#endif
+    if (fdx && fdx->isVirtual())
+        fdx = NULL;
+
+    return fdx;
+}
+
+
+/****************************** WithScopeSymbol ******************************/
+
+WithScopeSymbol::WithScopeSymbol(WithStatement *withstate)
+    : ScopeDsymbol()
+{
+    this->withstate = withstate;
+}
+
+Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("WithScopeSymbol::search(%s)\n", ident->toChars());
+    if (flags & SearchImportsOnly)
+        return NULL;
+
+    // Acts as proxy to the with class declaration
+    Dsymbol *s = NULL;
+    Expression *eold = NULL;
+    for (Expression *e = withstate->exp; e != eold; e = resolveAliasThis(_scope, e))
+    {
+        if (e->op == TOKscope)
+        {
+            s = ((ScopeExp *)e)->sds;
+        }
+        else if (e->op == TOKtype)
+        {
+            s = e->type->toDsymbol(NULL);
+        }
+        else
+        {
+            Type *t = e->type->toBasetype();
+            s = t->toDsymbol(NULL);
+        }
+        if (s)
+        {
+            s = s->search(loc, ident, flags);
+            if (s)
+                return s;
+        }
+        eold = e;
+    }
+    return NULL;
+}
+
+/****************************** ArrayScopeSymbol ******************************/
+
+ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e)
+    : ScopeDsymbol()
+{
+    assert(e->op == TOKindex || e->op == TOKslice || e->op == TOKarray);
+    exp = e;
+    type = NULL;
+    td = NULL;
+    this->sc = sc;
+}
+
+ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t)
+    : ScopeDsymbol()
+{
+    exp = NULL;
+    type = t;
+    td = NULL;
+    this->sc = sc;
+}
+
+ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s)
+    : ScopeDsymbol()
+{
+    exp = NULL;
+    type = NULL;
+    td = s;
+    this->sc = sc;
+}
+
+Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags);
+    if (ident == Id::dollar)
+    {
+        VarDeclaration **pvar;
+        Expression *ce;
+
+    L1:
+        if (td)
+        {
+            /* $ gives the number of elements in the tuple
+             */
+            VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
+            Expression *e = new IntegerExp(Loc(), td->objects->dim, Type::tsize_t);
+            v->_init = new ExpInitializer(Loc(), e);
+            v->storage_class |= STCtemp | STCstatic | STCconst;
+            v->semantic(sc);
+            return v;
+        }
+
+        if (type)
+        {
+            /* $ gives the number of type entries in the type tuple
+             */
+            VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
+            Expression *e = new IntegerExp(Loc(), type->arguments->dim, Type::tsize_t);
+            v->_init = new ExpInitializer(Loc(), e);
+            v->storage_class |= STCtemp | STCstatic | STCconst;
+            v->semantic(sc);
+            return v;
+        }
+
+        if (exp->op == TOKindex)
+        {
+            /* array[index] where index is some function of $
+             */
+            IndexExp *ie = (IndexExp *)exp;
+            pvar = &ie->lengthVar;
+            ce = ie->e1;
+        }
+        else if (exp->op == TOKslice)
+        {
+            /* array[lwr .. upr] where lwr or upr is some function of $
+             */
+            SliceExp *se = (SliceExp *)exp;
+            pvar = &se->lengthVar;
+            ce = se->e1;
+        }
+        else if (exp->op == TOKarray)
+        {
+            /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
+             * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
+             */
+            ArrayExp *ae = (ArrayExp *)exp;
+            pvar = &ae->lengthVar;
+            ce = ae->e1;
+        }
+        else
+        {
+            /* Didn't find $, look in enclosing scope(s).
+             */
+            return NULL;
+        }
+
+        while (ce->op == TOKcomma)
+            ce = ((CommaExp *)ce)->e2;
+
+        /* If we are indexing into an array that is really a type
+         * tuple, rewrite this as an index into a type tuple and
+         * try again.
+         */
+        if (ce->op == TOKtype)
+        {
+            Type *t = ((TypeExp *)ce)->type;
+            if (t->ty == Ttuple)
+            {
+                type = (TypeTuple *)t;
+                goto L1;
+            }
+        }
+
+        /* *pvar is lazily initialized, so if we refer to $
+         * multiple times, it gets set only once.
+         */
+        if (!*pvar)             // if not already initialized
+        {
+            /* Create variable v and set it to the value of $
+             */
+            VarDeclaration *v;
+            Type *t;
+            if (ce->op == TOKtuple)
+            {
+                /* It is for an expression tuple, so the
+                 * length will be a const.
+                 */
+                Expression *e = new IntegerExp(Loc(), ((TupleExp *)ce)->exps->dim, Type::tsize_t);
+                v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, new ExpInitializer(Loc(), e));
+                v->storage_class |= STCtemp | STCstatic | STCconst;
+            }
+            else if (ce->type && (t = ce->type->toBasetype()) != NULL &&
+                     (t->ty == Tstruct || t->ty == Tclass))
+            {
+                // Look for opDollar
+                assert(exp->op == TOKarray || exp->op == TOKslice);
+                AggregateDeclaration *ad = isAggregate(t);
+                assert(ad);
+
+                Dsymbol *s = ad->search(loc, Id::opDollar);
+                if (!s)  // no dollar exists -- search in higher scope
+                    return NULL;
+                s = s->toAlias();
+
+                Expression *e = NULL;
+                // Check for multi-dimensional opDollar(dim) template.
+                if (TemplateDeclaration *td = s->isTemplateDeclaration())
+                {
+                    dinteger_t dim = 0;
+                    if (exp->op == TOKarray)
+                    {
+                        dim = ((ArrayExp *)exp)->currentDimension;
+                    }
+                    else if (exp->op == TOKslice)
+                    {
+                        dim = 0; // slices are currently always one-dimensional
+                    }
+                    else
+                    {
+                        assert(0);
+                    }
+
+                    Objects *tiargs = new Objects();
+                    Expression *edim = new IntegerExp(Loc(), dim, Type::tsize_t);
+                    edim = ::semantic(edim, sc);
+                    tiargs->push(edim);
+                    e = new DotTemplateInstanceExp(loc, ce, td->ident, tiargs);
+                }
+                else
+                {
+                    /* opDollar exists, but it's not a template.
+                     * This is acceptable ONLY for single-dimension indexing.
+                     * Note that it's impossible to have both template & function opDollar,
+                     * because both take no arguments.
+                     */
+                    if (exp->op == TOKarray && ((ArrayExp *)exp)->arguments->dim != 1)
+                    {
+                        exp->error("%s only defines opDollar for one dimension", ad->toChars());
+                        return NULL;
+                    }
+                    Declaration *d = s->isDeclaration();
+                    assert(d);
+                    e = new DotVarExp(loc, ce, d);
+                }
+                e = ::semantic(e, sc);
+                if (!e->type)
+                    exp->error("%s has no value", e->toChars());
+                t = e->type->toBasetype();
+                if (t && t->ty == Tfunction)
+                    e = new CallExp(e->loc, e);
+                v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(Loc(), e));
+                v->storage_class |= STCtemp | STCctfe | STCrvalue;
+            }
+            else
+            {
+                /* For arrays, $ will either be a compile-time constant
+                 * (in which case its value in set during constant-folding),
+                 * or a variable (in which case an expression is created in
+                 * toir.c).
+                 */
+                VoidInitializer *e = new VoidInitializer(Loc());
+                e->type = Type::tsize_t;
+                v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, e);
+                v->storage_class |= STCtemp | STCctfe; // it's never a true static variable
+            }
+            *pvar = v;
+        }
+        (*pvar)->semantic(sc);
+        return (*pvar);
+    }
+    return NULL;
+}
+
+
+/****************************** DsymbolTable ******************************/
+
+DsymbolTable::DsymbolTable()
+{
+    tab = NULL;
+}
+
+Dsymbol *DsymbolTable::lookup(Identifier const * const ident)
+{
+    //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string);
+    return (Dsymbol *)dmd_aaGetRvalue(tab, (void *)ident);
+}
+
+Dsymbol *DsymbolTable::insert(Dsymbol *s)
+{
+    //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars());
+    Identifier *ident = s->ident;
+    Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, (void *)ident);
+    if (*ps)
+        return NULL;            // already in table
+    *ps = s;
+    return s;
+}
+
+Dsymbol *DsymbolTable::insert(Identifier const * const ident, Dsymbol *s)
+{
+    //printf("DsymbolTable::insert()\n");
+    Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, (void *)ident);
+    if (*ps)
+        return NULL;            // already in table
+    *ps = s;
+    return s;
+}
+
+Dsymbol *DsymbolTable::update(Dsymbol *s)
+{
+    Identifier *ident = s->ident;
+    Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, (void *)ident);
+    *ps = s;
+    return s;
+}
+
+/****************************** Prot ******************************/
+
+Prot::Prot()
+{
+    this->kind = PROTundefined;
+    this->pkg = NULL;
+}
+
+Prot::Prot(PROTKIND kind)
+{
+    this->kind = kind;
+    this->pkg = NULL;
+}
+
+/**
+ * Checks if `this` is superset of `other` restrictions.
+ * For example, "protected" is more restrictive than "public".
+ */
+bool Prot::isMoreRestrictiveThan(const Prot other) const
+{
+    return this->kind < other.kind;
+}
+
+/**
+ * Checks if `this` is absolutely identical protection attribute to `other`
+ */
+bool Prot::operator==(const Prot& other) const
+{
+    if (this->kind == other.kind)
+    {
+        if (this->kind == PROTpackage)
+            return this->pkg == other.pkg;
+        return true;
+    }
+    return false;
+}
+
+/**
+ * Checks if parent defines different access restrictions than this one.
+ *
+ * Params:
+ *  parent = protection attribute for scope that hosts this one
+ *
+ * Returns:
+ *  'true' if parent is already more restrictive than this one and thus
+ *  no differentiation is needed.
+ */
+bool Prot::isSubsetOf(const Prot& parent) const
+{
+    if (this->kind != parent.kind)
+        return false;
+
+    if (this->kind == PROTpackage)
+    {
+        if (!this->pkg)
+            return true;
+        if (!parent.pkg)
+            return false;
+        if (parent.pkg->isAncestorPackageOf(this->pkg))
+            return true;
+    }
+
+    return true;
+}
diff --git a/gcc/d/dfrontend/dsymbol.h b/gcc/d/dfrontend/dsymbol.h
new file mode 100644
index 00000000000..9537cf7ea1b
--- /dev/null
+++ b/gcc/d/dfrontend/dsymbol.h
@@ -0,0 +1,416 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dsymbol.h
+ */
+
+#ifndef DMD_DSYMBOL_H
+#define DMD_DSYMBOL_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "stringtable.h"
+
+#include "mars.h"
+#include "arraytypes.h"
+#include "visitor.h"
+
+class Identifier;
+struct Scope;
+class DsymbolTable;
+class Declaration;
+class ThisDeclaration;
+class TypeInfoDeclaration;
+class TupleDeclaration;
+class AliasDeclaration;
+class AggregateDeclaration;
+class EnumDeclaration;
+class ClassDeclaration;
+class InterfaceDeclaration;
+class StructDeclaration;
+class UnionDeclaration;
+class FuncDeclaration;
+class FuncAliasDeclaration;
+class OverDeclaration;
+class FuncLiteralDeclaration;
+class CtorDeclaration;
+class PostBlitDeclaration;
+class DtorDeclaration;
+class StaticCtorDeclaration;
+class StaticDtorDeclaration;
+class SharedStaticCtorDeclaration;
+class SharedStaticDtorDeclaration;
+class InvariantDeclaration;
+class UnitTestDeclaration;
+class NewDeclaration;
+class VarDeclaration;
+class AttribDeclaration;
+class Package;
+class Module;
+class Import;
+class Type;
+class TypeTuple;
+class WithStatement;
+class LabelDsymbol;
+class ScopeDsymbol;
+class ForwardingScopeDsymbol;
+class TemplateDeclaration;
+class TemplateInstance;
+class TemplateMixin;
+class ForwardingAttribDeclaration;
+class Nspace;
+class EnumMember;
+class WithScopeSymbol;
+class ArrayScopeSymbol;
+class SymbolDeclaration;
+class Expression;
+class DeleteDeclaration;
+class OverloadSet;
+struct AA;
+#ifdef IN_GCC
+typedef union tree_node Symbol;
+#else
+struct Symbol;
+#endif
+
+struct Ungag
+{
+    unsigned oldgag;
+
+    Ungag(unsigned old) : oldgag(old) {}
+    ~Ungag() { global.gag = oldgag; }
+};
+
+const char *mangleExact(FuncDeclaration *fd);
+void mangleToBuffer(Dsymbol *s, OutBuffer* buf);
+
+enum PROTKIND
+{
+    PROTundefined,
+    PROTnone,           // no access
+    PROTprivate,
+    PROTpackage,
+    PROTprotected,
+    PROTpublic,
+    PROTexport,
+};
+
+struct Prot
+{
+    PROTKIND kind;
+    Package *pkg;
+
+    Prot();
+    Prot(PROTKIND kind);
+
+    bool isMoreRestrictiveThan(const Prot other) const;
+    bool operator==(const Prot& other) const;
+    bool isSubsetOf(const Prot& other) const;
+};
+
+// in hdrgen.c
+void protectionToBuffer(OutBuffer *buf, Prot prot);
+const char *protectionToChars(PROTKIND kind);
+
+/* State of symbol in winding its way through the passes of the compiler
+ */
+enum PASS
+{
+    PASSinit,           // initial state
+    PASSsemantic,       // semantic() started
+    PASSsemanticdone,   // semantic() done
+    PASSsemantic2,      // semantic2() started
+    PASSsemantic2done,  // semantic2() done
+    PASSsemantic3,      // semantic3() started
+    PASSsemantic3done,  // semantic3() done
+    PASSinline,         // inline started
+    PASSinlinedone,     // inline done
+    PASSobj,            // toObjFile() run
+};
+
+/* Flags for symbol search
+ */
+enum
+{
+    IgnoreNone              = 0x00, // default
+    IgnorePrivateImports    = 0x01, // don't search private imports
+    IgnoreErrors            = 0x02, // don't give error messages
+    IgnoreAmbiguous         = 0x04, // return NULL if ambiguous
+    SearchLocalsOnly        = 0x08, // only look at locals (don't search imports)
+    SearchImportsOnly       = 0x10, // only look in imports
+    SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
+                                    // meaning don't search imports in that scope,
+                                    // because qualified module searches search
+                                    // their imports
+    IgnoreSymbolVisibility  = 0x80, // also find private and package protected symbols
+};
+
+typedef int (*Dsymbol_apply_ft_t)(Dsymbol *, void *);
+
+class Dsymbol : public RootObject
+{
+public:
+    Identifier *ident;
+    Dsymbol *parent;
+    Symbol *csym;               // symbol for code generator
+    Symbol *isym;               // import version of csym
+    const utf8_t *comment;      // documentation comment for this Dsymbol
+    Loc loc;                    // where defined
+    Scope *_scope;               // !=NULL means context to use for semantic()
+    const utf8_t *prettystring;
+    bool errors;                // this symbol failed to pass semantic()
+    PASS semanticRun;
+    DeprecatedDeclaration *depdecl; // customized deprecation message
+    UserAttributeDeclaration *userAttribDecl;   // user defined attributes
+    UnitTestDeclaration *ddocUnittest; // !=NULL means there's a ddoc unittest associated with this symbol (only use this with ddoc)
+
+    Dsymbol();
+    Dsymbol(Identifier *);
+    static Dsymbol *create(Identifier *);
+    const char *toChars();
+    virtual const char *toPrettyCharsHelper(); // helper to print fully qualified (template) arguments
+    Loc& getLoc();
+    const char *locToChars();
+    bool equals(RootObject *o);
+    bool isAnonymous();
+    void error(Loc loc, const char *format, ...);
+    void error(const char *format, ...);
+    void deprecation(Loc loc, const char *format, ...);
+    void deprecation(const char *format, ...);
+    void checkDeprecated(Loc loc, Scope *sc);
+    Module *getModule();
+    Module *getAccessModule();
+    Dsymbol *pastMixin();
+    Dsymbol *toParent();
+    Dsymbol *toParent2();
+    TemplateInstance *isInstantiated();
+    TemplateInstance *isSpeculative();
+    Ungag ungagSpeculative();
+
+    // kludge for template.isSymbol()
+    int dyncast() const { return DYNCAST_DSYMBOL; }
+
+    static Dsymbols *arraySyntaxCopy(Dsymbols *a);
+
+    virtual Identifier *getIdent();
+    virtual const char *toPrettyChars(bool QualifyTypes = false);
+    virtual const char *kind();
+    virtual Dsymbol *toAlias();                 // resolve real symbol
+    virtual Dsymbol *toAlias2();
+    virtual int apply(Dsymbol_apply_ft_t fp, void *param);
+    virtual void addMember(Scope *sc, ScopeDsymbol *sds);
+    virtual void setScope(Scope *sc);
+    virtual void importAll(Scope *sc);
+    virtual void semantic(Scope *sc);
+    virtual void semantic2(Scope *sc);
+    virtual void semantic3(Scope *sc);
+    virtual Dsymbol *search(Loc loc, Identifier *ident, int flags = IgnoreNone);
+    Dsymbol *search_correct(Identifier *id);
+    Dsymbol *searchX(Loc loc, Scope *sc, RootObject *id);
+    virtual bool overloadInsert(Dsymbol *s);
+    virtual d_uns64 size(Loc loc);
+    virtual bool isforwardRef();
+    virtual AggregateDeclaration *isThis();     // is a 'this' required to access the member
+    virtual bool isExport();                    // is Dsymbol exported?
+    virtual bool isImportedSymbol();            // is Dsymbol imported?
+    virtual bool isDeprecated();                // is Dsymbol deprecated?
+    virtual bool isOverloadable();
+    virtual LabelDsymbol *isLabel();            // is this a LabelDsymbol?
+    AggregateDeclaration *isMember();           // is this a member of an AggregateDeclaration?
+    AggregateDeclaration *isMember2();          // is this a member of an AggregateDeclaration?
+    ClassDeclaration *isClassMember();          // is this a member of a ClassDeclaration?
+    virtual Type *getType();                    // is this a type?
+    virtual bool needThis();                    // need a 'this' pointer?
+    virtual Prot prot();
+    virtual Dsymbol *syntaxCopy(Dsymbol *s);    // copy only syntax trees
+    virtual bool oneMember(Dsymbol **ps, Identifier *ident);
+    static bool oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident);
+    virtual void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+    virtual bool hasPointers();
+    virtual bool hasStaticCtorOrDtor();
+    virtual void addLocalClass(ClassDeclarations *) { }
+    virtual void checkCtorConstInit() { }
+
+    virtual void addComment(const utf8_t *comment);
+
+    bool inNonRoot();
+
+    // Eliminate need for dynamic_cast
+    virtual Package *isPackage() { return NULL; }
+    virtual Module *isModule() { return NULL; }
+    virtual EnumMember *isEnumMember() { return NULL; }
+    virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; }
+    virtual TemplateInstance *isTemplateInstance() { return NULL; }
+    virtual TemplateMixin *isTemplateMixin() { return NULL; }
+    virtual ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return NULL; }
+    virtual Nspace *isNspace() { return NULL; }
+    virtual Declaration *isDeclaration() { return NULL; }
+    virtual StorageClassDeclaration *isStorageClassDeclaration(){ return NULL; }
+    virtual ThisDeclaration *isThisDeclaration() { return NULL; }
+    virtual TypeInfoDeclaration *isTypeInfoDeclaration() { return NULL; }
+    virtual TupleDeclaration *isTupleDeclaration() { return NULL; }
+    virtual AliasDeclaration *isAliasDeclaration() { return NULL; }
+    virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; }
+    virtual FuncDeclaration *isFuncDeclaration() { return NULL; }
+    virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; }
+    virtual OverDeclaration *isOverDeclaration() { return NULL; }
+    virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; }
+    virtual CtorDeclaration *isCtorDeclaration() { return NULL; }
+    virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; }
+    virtual DtorDeclaration *isDtorDeclaration() { return NULL; }
+    virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; }
+    virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; }
+    virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; }
+    virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; }
+    virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; }
+    virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; }
+    virtual NewDeclaration *isNewDeclaration() { return NULL; }
+    virtual VarDeclaration *isVarDeclaration() { return NULL; }
+    virtual ClassDeclaration *isClassDeclaration() { return NULL; }
+    virtual StructDeclaration *isStructDeclaration() { return NULL; }
+    virtual UnionDeclaration *isUnionDeclaration() { return NULL; }
+    virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; }
+    virtual ScopeDsymbol *isScopeDsymbol() { return NULL; }
+    virtual ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return NULL; }
+    virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; }
+    virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; }
+    virtual Import *isImport() { return NULL; }
+    virtual EnumDeclaration *isEnumDeclaration() { return NULL; }
+    virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; }
+    virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; }
+    virtual AttribDeclaration *isAttribDeclaration() { return NULL; }
+    virtual AnonDeclaration *isAnonDeclaration() { return NULL; }
+    virtual OverloadSet *isOverloadSet() { return NULL; }
+    virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+// Dsymbol that generates a scope
+
+class ScopeDsymbol : public Dsymbol
+{
+public:
+    Dsymbols *members;          // all Dsymbol's in this scope
+    DsymbolTable *symtab;       // members[] sorted into table
+    unsigned endlinnum;         // the linnumber of the statement after the scope (0 if unknown)
+
+private:
+    Dsymbols *importedScopes;   // imported Dsymbol's
+    PROTKIND *prots;            // array of PROTKIND, one for each import
+
+    BitArray accessiblePackages, privateAccessiblePackages;
+
+public:
+    ScopeDsymbol();
+    ScopeDsymbol(Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Dsymbol *search(Loc loc, Identifier *ident, int flags = SearchLocalsOnly);
+    OverloadSet *mergeOverloadSet(Identifier *ident, OverloadSet *os, Dsymbol *s);
+    virtual void importScope(Dsymbol *s, Prot protection);
+    void addAccessiblePackage(Package *p, Prot protection);
+    virtual bool isPackageAccessible(Package *p, Prot protection, int flags = 0);
+    bool isforwardRef();
+    static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2);
+    const char *kind();
+    FuncDeclaration *findGetMembers();
+    virtual Dsymbol *symtabInsert(Dsymbol *s);
+    virtual Dsymbol *symtabLookup(Dsymbol *s, Identifier *id);
+    bool hasStaticCtorOrDtor();
+
+    static size_t dim(Dsymbols *members);
+    static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL);
+
+    ScopeDsymbol *isScopeDsymbol() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// With statement scope
+
+class WithScopeSymbol : public ScopeDsymbol
+{
+public:
+    WithStatement *withstate;
+
+    WithScopeSymbol(WithStatement *withstate);
+    Dsymbol *search(Loc loc, Identifier *ident, int flags = SearchLocalsOnly);
+
+    WithScopeSymbol *isWithScopeSymbol() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// Array Index/Slice scope
+
+class ArrayScopeSymbol : public ScopeDsymbol
+{
+public:
+    Expression *exp;    // IndexExp or SliceExp
+    TypeTuple *type;    // for tuple[length]
+    TupleDeclaration *td;       // for tuples of objects
+    Scope *sc;
+
+    ArrayScopeSymbol(Scope *sc, Expression *e);
+    ArrayScopeSymbol(Scope *sc, TypeTuple *t);
+    ArrayScopeSymbol(Scope *sc, TupleDeclaration *td);
+    Dsymbol *search(Loc loc, Identifier *ident, int flags = IgnoreNone);
+
+    ArrayScopeSymbol *isArrayScopeSymbol() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// Overload Sets
+
+class OverloadSet : public Dsymbol
+{
+public:
+    Dsymbols a;         // array of Dsymbols
+
+    OverloadSet(Identifier *ident, OverloadSet *os = NULL);
+    void push(Dsymbol *s);
+    OverloadSet *isOverloadSet() { return this; }
+    const char *kind();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// Forwarding ScopeDsymbol
+
+class ForwardingScopeDsymbol : public ScopeDsymbol
+{
+    ScopeDsymbol *forward;
+
+    Dsymbol *symtabInsert(Dsymbol *s);
+    Dsymbol *symtabLookup(Dsymbol *s, Identifier *id);
+    void importScope(Dsymbol *s, Prot protection);
+    void semantic(Scope *sc);
+    const char *kind();
+
+    ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return this; }
+};
+
+// Table of Dsymbol's
+
+class DsymbolTable : public RootObject
+{
+public:
+    AA *tab;
+
+    DsymbolTable();
+
+    // Look up Identifier. Return Dsymbol if found, NULL if not.
+    Dsymbol *lookup(Identifier const * const ident);
+
+    // Insert Dsymbol in table. Return NULL if already there.
+    Dsymbol *insert(Dsymbol *s);
+
+    // Look for Dsymbol in table. If there, return it. If not, insert s and return that.
+    Dsymbol *update(Dsymbol *s);
+    Dsymbol *insert(Identifier const * const ident, Dsymbol *s);     // when ident and s are not the same
+};
+
+#endif /* DMD_DSYMBOL_H */
diff --git a/gcc/d/dfrontend/dtemplate.c b/gcc/d/dfrontend/dtemplate.c
new file mode 100644
index 00000000000..a956a9fe126
--- /dev/null
+++ b/gcc/d/dfrontend/dtemplate.c
@@ -0,0 +1,8703 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/template.c
+ */
+
+// Handle template implementation
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root.h"
+#include "aav.h"
+#include "rmem.h"
+#include "stringtable.h"
+#include "hash.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 "mars.h"
+#include "dsymbol.h"
+#include "identifier.h"
+#include "hdrgen.h"
+#include "id.h"
+#include "attrib.h"
+#include "tokens.h"
+
+#define LOG     0
+
+#define IDX_NOTFOUND (0x12345678)               // index is not found
+
+void mangleToBuffer(Expression *e, OutBuffer *buf);
+Type *rawTypeMerge(Type *t1, Type *t2);
+bool MODimplicitConv(MOD modfrom, MOD modto);
+MATCH MODmethodConv(MOD modfrom, MOD modto);
+MOD MODmerge(MOD mod1, MOD mod2);
+
+static size_t templateParameterLookup(Type *tparam, TemplateParameters *parameters);
+static int arrayObjectMatch(Objects *oa1, Objects *oa2);
+static unsigned char deduceWildHelper(Type *t, Type **at, Type *tparam);
+static MATCH deduceTypeHelper(Type *t, Type **at, Type *tparam);
+static Type *reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *initializerToExpression(Initializer *i, Type *t = NULL);
+bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
+
+/********************************************
+ * These functions substitute for dynamic_cast. dynamic_cast does not work
+ * on earlier versions of gcc.
+ */
+
+Expression *isExpression(RootObject *o)
+{
+    //return dynamic_cast<Expression *>(o);
+    if (!o || o->dyncast() != DYNCAST_EXPRESSION)
+        return NULL;
+    return (Expression *)o;
+}
+
+Dsymbol *isDsymbol(RootObject *o)
+{
+    //return dynamic_cast<Dsymbol *>(o);
+    if (!o || o->dyncast() != DYNCAST_DSYMBOL)
+        return NULL;
+    return (Dsymbol *)o;
+}
+
+Type *isType(RootObject *o)
+{
+    //return dynamic_cast<Type *>(o);
+    if (!o || o->dyncast() != DYNCAST_TYPE)
+        return NULL;
+    return (Type *)o;
+}
+
+Tuple *isTuple(RootObject *o)
+{
+    //return dynamic_cast<Tuple *>(o);
+    if (!o || o->dyncast() != DYNCAST_TUPLE)
+        return NULL;
+    return (Tuple *)o;
+}
+
+Parameter *isParameter(RootObject *o)
+{
+    //return dynamic_cast<Parameter *>(o);
+    if (!o || o->dyncast() != DYNCAST_PARAMETER)
+        return NULL;
+    return (Parameter *)o;
+}
+
+/**************************************
+ * Is this Object an error?
+ */
+bool isError(RootObject *o)
+{
+    Type *t = isType(o);
+    if (t)
+        return (t->ty == Terror);
+    Expression *e = isExpression(o);
+    if (e)
+        return (e->op == TOKerror || !e->type || e->type->ty == Terror);
+    Tuple *v = isTuple(o);
+    if (v)
+        return arrayObjectIsError(&v->objects);
+    Dsymbol *s = isDsymbol(o);
+    assert(s);
+    if (s->errors)
+        return true;
+    return s->parent ? isError(s->parent) : false;
+}
+
+/**************************************
+ * Are any of the Objects an error?
+ */
+bool arrayObjectIsError(Objects *args)
+{
+    for (size_t i = 0; i < args->dim; i++)
+    {
+        RootObject *o = (*args)[i];
+        if (isError(o))
+            return true;
+    }
+    return false;
+}
+
+/***********************
+ * Try to get arg as a type.
+ */
+
+Type *getType(RootObject *o)
+{
+    Type *t = isType(o);
+    if (!t)
+    {
+        Expression *e = isExpression(o);
+        if (e)
+            t = e->type;
+    }
+    return t;
+}
+
+Dsymbol *getDsymbol(RootObject *oarg)
+{
+    //printf("getDsymbol()\n");
+    //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(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)
+        {
+            if (((FuncExp *)ea)->td)
+                sa = ((FuncExp *)ea)->td;
+            else
+                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;
+}
+
+/***********************
+ * Try to get value from manifest constant
+ */
+
+static Expression *getValue(Expression *e)
+{
+    if (e && e->op == TOKvar)
+    {
+        VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
+        if (v && v->storage_class & STCmanifest)
+        {
+            e = v->getConstInitializer();
+        }
+    }
+    return e;
+}
+
+static Expression *getValue(Dsymbol *&s)
+{
+    Expression *e = NULL;
+    if (s)
+    {
+        VarDeclaration *v = s->isVarDeclaration();
+        if (v && v->storage_class & STCmanifest)
+        {
+            e = v->getConstInitializer();
+        }
+    }
+    return e;
+}
+
+/**********************************
+ * Return true if e could be valid only as a template value parameter.
+ * Return false if it might be an alias or tuple.
+ * (Note that even in this case, it could still turn out to be a value).
+ */
+bool definitelyValueParameter(Expression *e)
+{
+    // None of these can be value parameters
+    if (e->op == TOKtuple || e->op == TOKscope  ||
+        e->op == TOKtype || e->op == TOKdottype ||
+        e->op == TOKtemplate ||  e->op == TOKdottd ||
+        e->op == TOKfunction || e->op == TOKerror ||
+        e->op == TOKthis || e->op == TOKsuper)
+        return false;
+
+    if (e->op != TOKdotvar)
+        return true;
+
+    /* Template instantiations involving a DotVar expression are difficult.
+     * In most cases, they should be treated as a value parameter, and interpreted.
+     * But they might also just be a fully qualified name, which should be treated
+     * as an alias.
+     */
+
+    // x.y.f cannot be a value
+    FuncDeclaration *f = ((DotVarExp *)e)->var->isFuncDeclaration();
+    if (f)
+        return false;
+
+    while (e->op == TOKdotvar)
+    {
+        e = ((DotVarExp *)e)->e1;
+    }
+    // this.x.y and super.x.y couldn't possibly be valid values.
+    if (e->op == TOKthis || e->op == TOKsuper)
+        return false;
+
+    // e.type.x could be an alias
+    if (e->op == TOKdottype)
+        return false;
+
+    // var.x.y is the only other possible form of alias
+    if (e->op != TOKvar)
+        return true;
+
+    VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
+
+    // func.x.y is not an alias
+    if (!v)
+        return true;
+
+    // TODO: Should we force CTFE if it is a global constant?
+
+    return false;
+}
+
+static Expression *getExpression(RootObject *o)
+{
+    Dsymbol *s = isDsymbol(o);
+    return s ? getValue(s) : getValue(isExpression(o));
+}
+
+/******************************
+ * If o1 matches o2, return true.
+ * Else, return false.
+ */
+
+static bool match(RootObject *o1, RootObject *o2)
+{
+    //printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n",
+    //       o1, o1->toChars(), o1->dyncast(), o2, o2->toChars(), o2->dyncast());
+
+    /* 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.
+     */
+
+    /* Manifest constants should be compared by their values,
+     * at least in template arguments.
+     */
+
+    if (Type *t1 = isType(o1))
+    {
+        Type *t2 = isType(o2);
+        if (!t2)
+            goto Lnomatch;
+
+        //printf("\tt1 = %s\n", t1->toChars());
+        //printf("\tt2 = %s\n", t2->toChars());
+        if (!t1->equals(t2))
+            goto Lnomatch;
+
+        goto Lmatch;
+    }
+    if (Expression *e1 = getExpression(o1))
+    {
+        Expression *e2 = getExpression(o2);
+        if (!e2)
+            goto Lnomatch;
+
+        //printf("\te1 = %s %s %s\n", e1->type->toChars(), Token::toChars(e1->op), e1->toChars());
+        //printf("\te2 = %s %s %s\n", e2->type->toChars(), Token::toChars(e2->op), e2->toChars());
+        if (!e1->equals(e2))
+            goto Lnomatch;
+
+        goto Lmatch;
+    }
+    if (Dsymbol *s1 = isDsymbol(o1))
+    {
+        Dsymbol *s2 = isDsymbol(o2);
+        if (!s2)
+            goto Lnomatch;
+
+        //printf("\ts1 = %s\n", s1->toChars());
+        //printf("\ts2 = %s\n", s2->toChars());
+        if (!s1->equals(s2))
+            goto Lnomatch;
+        if (s1->parent != s2->parent && !s1->isFuncDeclaration() && !s2->isFuncDeclaration())
+            goto Lnomatch;
+
+        goto Lmatch;
+    }
+    if (Tuple *u1 = isTuple(o1))
+    {
+        Tuple *u2 = isTuple(o2);
+        if (!u2)
+            goto Lnomatch;
+
+        //printf("\tu1 = %s\n", u1->toChars());
+        //printf("\tu2 = %s\n", u2->toChars());
+        if (!arrayObjectMatch(&u1->objects, &u2->objects))
+            goto Lnomatch;
+
+        goto Lmatch;
+    }
+Lmatch:
+    //printf("\t-> match\n");
+    return true;
+
+Lnomatch:
+    //printf("\t-> nomatch\n");
+    return false;
+}
+
+
+/************************************
+ * Match an array of them.
+ */
+int arrayObjectMatch(Objects *oa1, Objects *oa2)
+{
+    if (oa1 == oa2)
+        return 1;
+    if (oa1->dim != oa2->dim)
+        return 0;
+    for (size_t j = 0; j < oa1->dim; j++)
+    {
+        RootObject *o1 = (*oa1)[j];
+        RootObject *o2 = (*oa2)[j];
+        if (!match(o1, o2))
+        {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+
+/************************************
+ * Computes hash of expression.
+ * Handles all Expression classes and MUST match their equals method,
+ * i.e. e1->equals(e2) implies expressionHash(e1) == expressionHash(e2).
+ */
+static hash_t expressionHash(Expression *e)
+{
+    switch (e->op)
+    {
+    case TOKint64:
+        return (size_t) ((IntegerExp *)e)->getInteger();
+
+    case TOKfloat64:
+        return CTFloat::hash(((RealExp *)e)->value);
+
+    case TOKcomplex80:
+    {
+        ComplexExp *ce = (ComplexExp *)e;
+        return mixHash(CTFloat::hash(ce->toReal()), CTFloat::hash(ce->toImaginary()));
+    }
+
+    case TOKidentifier:
+        return (size_t)(void *) ((IdentifierExp *)e)->ident;
+
+    case TOKnull:
+        return (size_t)(void *) ((NullExp *)e)->type;
+
+    case TOKstring:
+    {
+        StringExp *se = (StringExp *)e;
+        return calcHash((const char *)se->string, se->len * se->sz);
+    }
+
+    case TOKtuple:
+    {
+        TupleExp *te = (TupleExp *)e;
+        size_t hash = 0;
+        hash += te->e0 ? expressionHash(te->e0) : 0;
+        for (size_t i = 0; i < te->exps->dim; i++)
+        {
+            Expression *elem = (*te->exps)[i];
+            hash = mixHash(hash, expressionHash(elem));
+        }
+        return hash;
+    }
+
+    case TOKarrayliteral:
+    {
+        ArrayLiteralExp *ae = (ArrayLiteralExp *)e;
+        size_t hash = 0;
+        for (size_t i = 0; i < ae->elements->dim; i++)
+            hash = mixHash(hash, expressionHash(ae->getElement(i)));
+        return hash;
+    }
+
+    case TOKassocarrayliteral:
+    {
+        AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
+        size_t hash = 0;
+        for (size_t i = 0; i < ae->keys->dim; i++)
+            // reduction needs associative op as keys are unsorted (use XOR)
+            hash ^= mixHash(expressionHash((*ae->keys)[i]), expressionHash((*ae->values)[i]));
+        return hash;
+    }
+
+    case TOKstructliteral:
+    {
+        StructLiteralExp *se = (StructLiteralExp *)e;
+        size_t hash = 0;
+        for (size_t i = 0; i < se->elements->dim; i++)
+        {
+            Expression *elem = (*se->elements)[i];
+            hash = mixHash(hash, elem ? expressionHash(elem) : 0);
+        }
+        return hash;
+    }
+
+    case TOKvar:
+        return (size_t)(void *) ((VarExp *)e)->var;
+
+    case TOKfunction:
+        return (size_t)(void *) ((FuncExp *)e)->fd;
+
+    default:
+        // no custom equals for this expression
+        // equals based on identity
+        return (size_t)(void *) e;
+    }
+}
+
+
+/************************************
+ * Return hash of Objects.
+ */
+static hash_t arrayObjectHash(Objects *oa1)
+{
+    hash_t hash = 0;
+    for (size_t j = 0; j < oa1->dim; j++)
+    {
+        /* Must follow the logic of match()
+         */
+        RootObject *o1 = (*oa1)[j];
+        if (Type *t1 = isType(o1))
+            hash = mixHash(hash, (size_t)t1->deco);
+        else if (Expression *e1 = getExpression(o1))
+            hash = mixHash(hash, expressionHash(e1));
+        else if (Dsymbol *s1 = isDsymbol(o1))
+        {
+            FuncAliasDeclaration *fa1 = s1->isFuncAliasDeclaration();
+            if (fa1)
+                s1 = fa1->toAliasFunc();
+            hash = mixHash(hash, mixHash((size_t)(void *)s1->getIdent(), (size_t)(void *)s1->parent));
+        }
+        else if (Tuple *u1 = isTuple(o1))
+            hash = mixHash(hash, arrayObjectHash(&u1->objects));
+    }
+    return hash;
+}
+
+RootObject *objectSyntaxCopy(RootObject *o)
+{
+    if (!o)
+        return NULL;
+    if (Type *t = isType(o))
+        return t->syntaxCopy();
+    if (Expression *e = isExpression(o))
+        return e->syntaxCopy();
+    return o;
+}
+
+
+/* ======================== TemplateDeclaration ============================= */
+
+TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id,
+        TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs, bool ismixin, bool literal)
+    : 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 = (*parameters)[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->funcroot = NULL;
+    this->onemember = NULL;
+    this->literal = literal;
+    this->ismixin = ismixin;
+    this->isstatic = true;
+    this->previous = NULL;
+    this->protection = Prot(PROTundefined);
+    this->instances = NULL;
+
+    // Compute in advance for Ddoc's use
+    // Bugzilla 11153: ident could be NULL if parsing fails.
+    if (members && ident)
+    {
+        Dsymbol *s;
+        if (Dsymbol::oneMembers(members, &s, ident) && s)
+        {
+            onemember = s;
+            s->parent = this;
+        }
+    }
+}
+
+Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *)
+{
+    //printf("TemplateDeclaration::syntaxCopy()\n");
+    TemplateParameters *p = NULL;
+    if (parameters)
+    {
+        p = new TemplateParameters();
+        p->setDim(parameters->dim);
+        for (size_t i = 0; i < p->dim; i++)
+            (*p)[i] = (*parameters)[i]->syntaxCopy();
+    }
+    return new TemplateDeclaration(loc, ident, p,
+        constraint ? constraint->syntaxCopy() : NULL,
+        Dsymbol::arraySyntaxCopy(members), ismixin, literal);
+}
+
+void TemplateDeclaration::semantic(Scope *sc)
+{
+#if LOG
+    printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars());
+    printf("sc->stc = %llx\n", sc->stc);
+    printf("sc->module = %s\n", sc->_module->toChars());
+#endif
+    if (semanticRun != PASSinit)
+        return;         // semantic() already run
+    semanticRun = PASSsemantic;
+
+    // Remember templates defined in module object that we need to know about
+    if (sc->_module && sc->_module->ident == Id::object)
+    {
+        if (ident == Id::RTInfo)
+            Type::rtinfo = this;
+    }
+
+    /* Remember Scope for later instantiations, but make
+     * a copy since attributes can change.
+     */
+    if (!this->_scope)
+    {
+        this->_scope = sc->copy();
+        this->_scope->setNoFree();
+    }
+
+    // Set up scope for parameters
+    ScopeDsymbol *paramsym = new ScopeDsymbol();
+    paramsym->parent = sc->parent;
+    Scope *paramscope = sc->push(paramsym);
+    paramscope->stc = 0;
+
+    if (!parent)
+        parent = sc->parent;
+
+    isstatic = toParent()->isModule() || (_scope->stc & STCstatic);
+
+    protection = sc->protection;
+
+    if (global.params.doDocComments)
+    {
+        origParameters = new TemplateParameters();
+        origParameters->setDim(parameters->dim);
+        for (size_t i = 0; i < parameters->dim; i++)
+        {
+            TemplateParameter *tp = (*parameters)[i];
+            (*origParameters)[i] = tp->syntaxCopy();
+        }
+    }
+
+    for (size_t i = 0; i < parameters->dim; i++)
+    {
+        TemplateParameter *tp = (*parameters)[i];
+
+        if (!tp->declareParameter(paramscope))
+        {
+            error(tp->loc, "parameter '%s' multiply defined", tp->ident->toChars());
+            errors = true;
+        }
+        if (!tp->semantic(paramscope, parameters))
+        {
+            errors = true;
+        }
+        if (i + 1 != parameters->dim && tp->isTemplateTupleParameter())
+        {
+            error("template tuple parameter must be last one");
+            errors = true;
+        }
+    }
+
+    /* Calculate TemplateParameter::dependent
+     */
+    TemplateParameters tparams;
+    tparams.setDim(1);
+    for (size_t i = 0; i < parameters->dim; i++)
+    {
+        TemplateParameter *tp = (*parameters)[i];
+        tparams[0] = tp;
+
+        for (size_t j = 0; j < parameters->dim; j++)
+        {
+            // Skip cases like: X(T : T)
+            if (i == j)
+                continue;
+
+            if (TemplateTypeParameter *ttp = (*parameters)[j]->isTemplateTypeParameter())
+            {
+                if (reliesOnTident(ttp->specType, &tparams))
+                    tp->dependent = true;
+            }
+            else if (TemplateAliasParameter *tap = (*parameters)[j]->isTemplateAliasParameter())
+            {
+                if (reliesOnTident(tap->specType, &tparams) ||
+                    reliesOnTident(isType(tap->specAlias), &tparams))
+                {
+                    tp->dependent = true;
+                }
+            }
+        }
+    }
+
+    paramscope->pop();
+
+    // Compute again
+    onemember = NULL;
+    if (members)
+    {
+        Dsymbol *s;
+        if (Dsymbol::oneMembers(members, &s, ident) && s)
+        {
+            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 true if successful; i.e. no conflict.
+ */
+
+bool TemplateDeclaration::overloadInsert(Dsymbol *s)
+{
+#if LOG
+    printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars());
+#endif
+    FuncDeclaration *fd = s->isFuncDeclaration();
+    if (fd)
+    {
+        if (funcroot)
+            return funcroot->overloadInsert(fd);
+        funcroot = fd;
+        return funcroot->overloadInsert(this);
+    }
+
+    TemplateDeclaration *td = s->isTemplateDeclaration();
+    if (!td)
+        return false;
+
+    TemplateDeclaration *pthis = this;
+    TemplateDeclaration **ptd;
+    for (ptd = &pthis; *ptd; ptd = &(*ptd)->overnext)
+    {
+    }
+
+    td->overroot = this;
+    *ptd = td;
+#if LOG
+    printf("\ttrue: no conflict\n");
+#endif
+    return true;
+}
+
+/****************************
+ * Check to see if constraint is satisfied.
+ */
+bool TemplateDeclaration::evaluateConstraint(
+        TemplateInstance *ti, Scope *sc, Scope *paramscope,
+        Objects *dedargs, FuncDeclaration *fd)
+{
+    /* Detect recursive attempts to instantiate this template declaration,
+     * Bugzilla 4072
+     *  void foo(T)(T x) if (is(typeof(foo(x)))) { }
+     *  static assert(!is(typeof(foo(7))));
+     * Recursive attempts are regarded as a constraint failure.
+     */
+    /* There's a chicken-and-egg problem here. We don't know yet if this template
+     * instantiation will be a local one (enclosing is set), and we won't know until
+     * after selecting the correct template. Thus, function we're nesting inside
+     * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel().
+     * Workaround the problem by setting a flag to relax the checking on frame errors.
+     */
+
+    for (TemplatePrevious *p = previous; p; p = p->prev)
+    {
+        if (arrayObjectMatch(p->dedargs, dedargs))
+        {
+            //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars());
+            /* It must be a subscope of p->sc, other scope chains are not recursive
+             * instantiations.
+             */
+            for (Scope *scx = sc; scx; scx = scx->enclosing)
+            {
+                if (scx == p->sc)
+                    return false;
+            }
+        }
+        /* BUG: should also check for ref param differences
+         */
+    }
+
+    TemplatePrevious pr;
+    pr.prev    = previous;
+    pr.sc      = paramscope;
+    pr.dedargs = dedargs;
+    previous = &pr;                 // add this to threaded list
+
+    unsigned int nerrors = global.errors;
+
+    Scope *scx = paramscope->push(ti);
+    scx->parent = ti;
+    scx->tinst = NULL;
+    scx->minst = NULL;
+
+    assert(!ti->symtab);
+    if (fd)
+    {
+        /* Declare all the function parameters as variables and add them to the scope
+         * Making parameters is similar to FuncDeclaration::semantic3
+         */
+        TypeFunction *tf = (TypeFunction *)fd->type;
+        assert(tf->ty == Tfunction);
+
+        scx->parent = fd;
+
+        Parameters *fparameters = tf->parameters;
+        int fvarargs = tf->varargs;
+
+        size_t nfparams = Parameter::dim(fparameters);
+        for (size_t i = 0; i < nfparams; i++)
+        {
+            Parameter *fparam = Parameter::getNth(fparameters, i);
+            fparam->storageClass &= (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor);
+            fparam->storageClass |= STCparameter;
+            if (fvarargs == 2 && i + 1 == nfparams)
+                fparam->storageClass |= STCvariadic;
+        }
+        for (size_t i = 0; i < fparameters->dim; i++)
+        {
+            Parameter *fparam = (*fparameters)[i];
+            if (!fparam->ident)
+                continue;                       // don't add it, if it has no name
+            VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL);
+            v->storage_class = fparam->storageClass;
+            v->semantic(scx);
+            if (!ti->symtab)
+                ti->symtab = new DsymbolTable();
+            if (!scx->insert(v))
+                error("parameter %s.%s is already defined", toChars(), v->toChars());
+            else
+                v->parent = fd;
+        }
+        if (isstatic)
+            fd->storage_class |= STCstatic;
+
+        fd->vthis = fd->declareThis(scx, fd->isThis());
+    }
+
+    Expression *e = constraint->syntaxCopy();
+
+    assert(ti->inst == NULL);
+    ti->inst = ti;  // temporary instantiation to enable genIdent()
+
+    scx->flags |= SCOPEconstraint;
+    bool errors = false;
+    bool result = evalStaticCondition(scx, constraint, e, errors);
+    ti->inst = NULL;
+    ti->symtab = NULL;
+    scx = scx->pop();
+    previous = pr.prev;             // unlink from threaded list
+    if (errors)
+        return false;
+    return result;
+}
+
+/***************************************
+ * 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(Scope *sc, TemplateInstance *ti,
+        Objects *dedtypes, Expressions *fargs, int flag)
+{
+#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)[0]);
+#endif
+    MATCH m;
+    size_t dedtypes_dim = dedtypes->dim;
+
+    dedtypes->zero();
+
+    if (errors)
+        return MATCHnomatch;
+
+    size_t 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);
+
+    assert(_scope);
+
+    // Set up scope for template parameters
+    ScopeDsymbol *paramsym = new ScopeDsymbol();
+    paramsym->parent = _scope->parent;
+    Scope *paramscope = _scope->push(paramsym);
+    paramscope->tinst = ti;
+    paramscope->minst = sc->minst;
+    paramscope->callsc = sc;
+    paramscope->stc = 0;
+
+    // Attempt type deduction
+    m = MATCHexact;
+    for (size_t i = 0; i < dedtypes_dim; i++)
+    {
+        MATCH m2;
+        TemplateParameter *tp = (*parameters)[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
+
+        m2 = tp->matchArg(ti->loc, paramscope, ti->tiargs, i, parameters, dedtypes, &sparam);
+        //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))    // TODO: This check can make more early
+            goto Lnomatch;                  // in TemplateDeclaration::semantic, and
+                                            // then we don't need to make sparam if flags == 0
+    }
+
+    if (!flag)
+    {
+        /* Any parameter left without a type gets the type of
+         * its corresponding arg
+         */
+        for (size_t i = 0; i < dedtypes_dim; i++)
+        {
+            if (!(*dedtypes)[i])
+            {
+                assert(i < ti->tiargs->dim);
+                (*dedtypes)[i] = (Type *)(*ti->tiargs)[i];
+            }
+        }
+    }
+
+    if (m > MATCHnomatch && constraint && !flag)
+    {
+        if (ti->hasNestedArgs(ti->tiargs, this->isstatic))  // TODO: should gag error
+            ti->parent = ti->enclosing;
+        else
+            ti->parent = this->parent;
+
+        // Similar to doHeaderInstantiation
+        FuncDeclaration *fd = onemember ? onemember->isFuncDeclaration() : NULL;
+        if (fd)
+        {
+            assert(fd->type->ty == Tfunction);
+            TypeFunction *tf = (TypeFunction *)fd->type->syntaxCopy();
+
+            fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, tf);
+            fd->parent = ti;
+            fd->inferRetType = true;
+
+            // Shouldn't run semantic on default arguments and return type.
+            for (size_t i = 0; i < tf->parameters->dim; i++)
+                (*tf->parameters)[i]->defaultArg = NULL;
+            tf->next = NULL;
+
+            // Resolve parameter types and 'auto ref's.
+            tf->fargs = fargs;
+            unsigned olderrors = global.startGagging();
+            fd->type = tf->semantic(loc, paramscope);
+            if (global.endGagging(olderrors))
+            {
+                assert(fd->type->ty != Tfunction);
+                goto Lnomatch;
+            }
+            assert(fd->type->ty == Tfunction);
+            fd->originalType = fd->type;    // for mangling
+        }
+
+        // TODO: dedtypes => ti->tiargs ?
+        if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd))
+            goto Lnomatch;
+    }
+
+#if LOGM
+    // Print out the results
+    printf("--------------------------\n");
+    printf("template %s\n", toChars());
+    printf("instance %s\n", ti->toChars());
+    if (m > MATCHnomatch)
+    {
+        for (size_t i = 0; i < dedtypes_dim; i++)
+        {
+            TemplateParameter *tp = (*parameters)[i];
+            RootObject *oarg;
+
+            printf(" [%d]", i);
+
+            if (i < ti->tiargs->dim)
+                oarg = (*ti->tiargs)[i];
+            else
+                oarg = NULL;
+            tp->print(oarg, (*dedtypes)[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(Scope *sc, TemplateDeclaration *td2, Expressions *fargs)
+{
+#define LOG_LEASTAS     0
+
+#if LOG_LEASTAS
+    printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars());
+#endif
+
+    /* 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(Loc(), ident);      // create dummy template instance
+    // Set type arguments to dummy template instance to be types
+    // generated from the parameters to this template declaration
+    ti.tiargs = new Objects();
+    ti.tiargs->reserve(parameters->dim);
+    for (size_t i = 0; i < parameters->dim; i++)
+    {
+        TemplateParameter *tp = (*parameters)[i];
+        if (tp->dependent)
+            break;
+        RootObject *p = (RootObject *)tp->dummyArg();
+        if (!p)
+            break;
+
+        ti.tiargs->push(p);
+    }
+
+    // Temporary Array to hold deduced types
+    Objects dedtypes;
+    dedtypes.setDim(td2->parameters->dim);
+
+    // Attempt a type deduction
+    MATCH m = td2->matchWithInstance(sc, &ti, &dedtypes, fargs, 1);
+    if (m > MATCHnomatch)
+    {
+        /* A non-variadic template is more specialized than a
+         * variadic one.
+         */
+        TemplateTupleParameter *tp = isVariadic();
+        if (tp && !tp->dependent && !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;
+}
+
+static Expression *emptyArrayElement = NULL;
+
+class TypeDeduced : public Type
+{
+public:
+    Type *tded;
+    Expressions argexps;    // corresponding expressions
+    Types tparams;          // tparams[i]->mod
+
+    TypeDeduced(Type *tt, Expression *e, Type *tparam)
+        : Type(Tnone)
+    {
+        tded = tt;
+        argexps.push(e);
+        tparams.push(tparam);
+    }
+    void update(Expression *e, Type *tparam)
+    {
+        argexps.push(e);
+        tparams.push(tparam);
+    }
+    void update(Type *tt, Expression *e, Type *tparam)
+    {
+        tded = tt;
+        argexps.push(e);
+        tparams.push(tparam);
+    }
+    MATCH matchAll(Type *tt)
+    {
+        MATCH match = MATCHexact;
+        for (size_t j = 0; j < argexps.dim; j++)
+        {
+            Expression *e = argexps[j];
+            assert(e);
+            if (e == emptyArrayElement)
+                continue;
+
+            Type *t = tt->addMod(tparams[j]->mod)->substWildTo(MODconst);
+
+            MATCH m = e->implicitConvTo(t);
+            if (match > m)
+                match = m;
+            if (match <= MATCHnomatch)
+                break;
+        }
+        return match;
+    }
+};
+
+/*************************************************
+ * Match function arguments against a specific template function.
+ * Input:
+ *      ti
+ *      sc              instantiation scope
+ *      fd
+ *      tthis           'this' argument if !NULL
+ *      fargs           arguments to function
+ * Output:
+ *      fd              Partially instantiated function declaration
+ *      ti->tdtypes     Expression/Type deduced template arguments
+ * Returns:
+ *      match level
+ *          bit 0-3     Match template parameters by inferred template arguments
+ *          bit 4-7     Match template parameters by initial template arguments
+ */
+
+MATCH TemplateDeclaration::deduceFunctionTemplateMatch(
+        TemplateInstance *ti, Scope *sc,
+        FuncDeclaration *&fd, Type *tthis, Expressions *fargs)
+{
+    size_t nfparams;
+    size_t nfargs;
+    size_t ntargs;              // array size of tiargs
+    size_t fptupindex = IDX_NOTFOUND;
+    MATCH match = MATCHexact;
+    MATCH matchTiargs = MATCHexact;
+    Parameters *fparameters;            // function parameter list
+    int fvarargs;                       // function varargs
+    unsigned wildmatch = 0;
+    size_t inferStart = 0;
+
+    Loc instLoc = ti->loc;
+    Objects *tiargs = ti->tiargs;
+    Objects *dedargs = new Objects();
+    Objects* dedtypes = &ti->tdtypes;   // for T:T*, the dedargs is the T*, dedtypes is the T
+
+#if 0
+    printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars());
+    for (size_t i = 0; i < (fargs ? fargs->dim : 0); i++)
+    {
+        Expression *e = (*fargs)[i];
+        printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars());
+    }
+    printf("fd = %s\n", fd->toChars());
+    printf("fd->type = %s\n", fd->type->toChars());
+    if (tthis)
+        printf("tthis = %s\n", tthis->toChars());
+#endif
+
+    assert(_scope);
+
+    dedargs->setDim(parameters->dim);
+    dedargs->zero();
+
+    dedtypes->setDim(parameters->dim);
+    dedtypes->zero();
+
+    if (errors || fd->errors)
+        return MATCHnomatch;
+
+    // Set up scope for parameters
+    ScopeDsymbol *paramsym = new ScopeDsymbol();
+    paramsym->parent = _scope->parent;   // should use hasnestedArgs and enclosing?
+    Scope *paramscope = _scope->push(paramsym);
+    paramscope->tinst = ti;
+    paramscope->minst = sc->minst;
+    paramscope->callsc = sc;
+    paramscope->stc = 0;
+
+    TemplateTupleParameter *tp = isVariadic();
+    Tuple *declaredTuple = NULL;
+
+#if 0
+    for (size_t i = 0; i < dedargs->dim; i++)
+    {
+        printf("\tdedarg[%d] = ", i);
+        RootObject *oarg = (*dedargs)[i];
+        if (oarg) printf("%s", oarg->toChars());
+        printf("\n");
+    }
+#endif
+
+
+    ntargs = 0;
+    if (tiargs)
+    {
+        // Set initial template arguments
+        ntargs = tiargs->dim;
+        size_t n = parameters->dim;
+        if (tp)
+            n--;
+        if (ntargs > n)
+        {
+            if (!tp)
+                goto Lnomatch;
+
+            /* The extra initial template arguments
+             * now form the tuple argument.
+             */
+            Tuple *t = new Tuple();
+            assert(parameters->dim);
+            (*dedargs)[parameters->dim - 1] = t;
+
+            t->objects.setDim(ntargs - n);
+            for (size_t i = 0; i < t->objects.dim; i++)
+            {
+                t->objects[i] = (*tiargs)[n + i];
+            }
+            declareParameter(paramscope, tp, t);
+            declaredTuple = t;
+        }
+        else
+            n = ntargs;
+
+        memcpy(dedargs->tdata(), tiargs->tdata(), n * sizeof(*dedargs->tdata()));
+
+        for (size_t i = 0; i < n; i++)
+        {
+            assert(i < parameters->dim);
+            Declaration *sparam = NULL;
+            MATCH m = (*parameters)[i]->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam);
+            //printf("\tdeduceType m = %d\n", m);
+            if (m <= MATCHnomatch)
+                goto Lnomatch;
+            if (m < matchTiargs)
+                matchTiargs = m;
+
+            sparam->semantic(paramscope);
+            if (!paramscope->insert(sparam))
+                goto Lnomatch;
+        }
+        if (n < parameters->dim && !declaredTuple)
+        {
+            inferStart = n;
+        }
+        else
+            inferStart = parameters->dim;
+        //printf("tiargs matchTiargs = %d\n", matchTiargs);
+    }
+#if 0
+    for (size_t i = 0; i < dedargs->dim; i++)
+    {
+        printf("\tdedarg[%d] = ", i);
+        RootObject *oarg = (*dedargs)[i];
+        if (oarg) printf("%s", oarg->toChars());
+        printf("\n");
+    }
+#endif
+
+    fparameters = fd->getParameters(&fvarargs);
+    nfparams = Parameter::dim(fparameters);     // number of function parameters
+    nfargs = fargs ? fargs->dim : 0;            // number of function arguments
+
+    /* Check for match of function arguments with variadic template
+     * parameter, such as:
+     *
+     * void foo(T, A...)(T t, A a);
+     * void main() { foo(1,2,3); }
+     */
+    if (tp)                             // if variadic
+    {
+        // TemplateTupleParameter always makes most lesser matching.
+        matchTiargs = MATCHconvert;
+
+        if (nfparams == 0 && nfargs != 0)               // if no function parameters
+        {
+            if (!declaredTuple)
+            {
+                Tuple *t = new Tuple();
+                //printf("t = %p\n", t);
+                (*dedargs)[parameters->dim - 1] = t;
+                declareParameter(paramscope, tp, t);
+                declaredTuple = t;
+            }
+        }
+        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++)
+            {
+                Parameter *fparam = (*fparameters)[fptupindex];
+                if (fparam->type->ty != Tident)
+                    continue;
+                TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
+                if (!tp->ident->equals(tid->ident) || tid->idents.dim)
+                    continue;
+
+                if (fvarargs)           // variadic function doesn't
+                    goto Lnomatch;      // go with variadic template
+
+                goto L1;
+            }
+            fptupindex = IDX_NOTFOUND;
+        L1:
+            ;
+        }
+    }
+
+    if (toParent()->isModule() || (_scope->stc & STCstatic))
+        tthis = NULL;
+    if (tthis)
+    {
+        bool hasttp = false;
+
+        // Match 'tthis' to any TemplateThisParameter's
+        for (size_t i = 0; i < parameters->dim; i++)
+        {
+            TemplateThisParameter *ttp = (*parameters)[i]->isTemplateThisParameter();
+            if (ttp)
+            {
+                hasttp = true;
+
+                Type *t = new TypeIdentifier(Loc(), ttp->ident);
+                MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes);
+                if (m <= MATCHnomatch)
+                    goto Lnomatch;
+                if (m < match)
+                    match = m;          // pick worst match
+            }
+        }
+
+        // Match attributes of tthis against attributes of fd
+        if (fd->type && !fd->isCtorDeclaration())
+        {
+            StorageClass stc = _scope->stc | fd->storage_class2;
+            // Propagate parent storage class (see bug 5504)
+            Dsymbol *p = parent;
+            while (p->isTemplateDeclaration() || p->isTemplateInstance())
+                p = p->parent;
+            AggregateDeclaration *ad = p->isAggregateDeclaration();
+            if (ad)
+                stc |= ad->storage_class;
+
+            unsigned char mod = fd->type->mod;
+            if (stc & STCimmutable)
+                mod = MODimmutable;
+            else
+            {
+                if (stc & (STCshared | STCsynchronized))
+                    mod |= MODshared;
+                if (stc & STCconst)
+                    mod |= MODconst;
+                if (stc & STCwild)
+                    mod |= MODwild;
+            }
+
+            unsigned char thismod = tthis->mod;
+            if (hasttp)
+                mod = MODmerge(thismod, mod);
+            MATCH m = MODmethodConv(thismod, mod);
+            if (m <= MATCHnomatch)
+                goto Lnomatch;
+            if (m < match)
+                match = m;
+        }
+    }
+
+    // Loop through the function parameters
+    {
+    //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple->objects.dim : 0);
+    //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple->toChars() : NULL);
+    size_t argi = 0;
+    size_t nfargs2 = nfargs;    // nfargs + supplied defaultArgs
+    for (size_t parami = 0; parami < nfparams; parami++)
+    {
+        Parameter *fparam = Parameter::getNth(fparameters, parami);
+
+        // Apply function parameter storage classes to parameter types
+        Type *prmtype = fparam->type->addStorageClass(fparam->storageClass);
+
+        Expression *farg;
+
+        /* See function parameters which wound up
+         * as part of a template tuple parameter.
+         */
+        if (fptupindex != IDX_NOTFOUND && parami == fptupindex)
+        {
+            assert(prmtype->ty == Tident);
+            TypeIdentifier *tid = (TypeIdentifier *)prmtype;
+            if (!declaredTuple)
+            {
+                /* The types of the function arguments
+                 * now form the tuple argument.
+                 */
+                declaredTuple = new Tuple();
+                (*dedargs)[parameters->dim - 1] = declaredTuple;
+
+                /* Count function parameters following a tuple parameter.
+                 * void foo(U, T...)(int y, T, U, int) {}  // rem == 2 (U, int)
+                 */
+                size_t rem = 0;
+                for (size_t j = parami + 1; j < nfparams; j++)
+                {
+                    Parameter *p = Parameter::getNth(fparameters, j);
+                    if (!reliesOnTident(p->type, parameters, inferStart))
+                    {
+                        Type *pt = p->type->syntaxCopy()->semantic(fd->loc, paramscope);
+                        rem += pt->ty == Ttuple ? ((TypeTuple *)pt)->arguments->dim : 1;
+                    }
+                    else
+                    {
+                        ++rem;
+                    }
+                }
+
+                if (nfargs2 - argi < rem)
+                    goto Lnomatch;
+                declaredTuple->objects.setDim(nfargs2 - argi - rem);
+                for (size_t i = 0; i < declaredTuple->objects.dim; i++)
+                {
+                    farg = (*fargs)[argi + i];
+
+                    // Check invalid arguments to detect errors early.
+                    if (farg->op == TOKerror || farg->type->ty == Terror)
+                        goto Lnomatch;
+
+                    if (!(fparam->storageClass & STClazy) && farg->type->ty == Tvoid)
+                        goto Lnomatch;
+
+                    Type *tt;
+                    MATCH m;
+                    if (unsigned char wm = deduceWildHelper(farg->type, &tt, tid))
+                    {
+                        wildmatch |= wm;
+                        m = MATCHconst;
+                    }
+                    else
+                    {
+                        m = deduceTypeHelper(farg->type, &tt, tid);
+                    }
+                    if (m <= MATCHnomatch)
+                        goto Lnomatch;
+                    if (m < match)
+                        match = m;
+
+                    /* Remove top const for dynamic array types and pointer types
+                     */
+                    if ((tt->ty == Tarray || tt->ty == Tpointer) &&
+                        !tt->isMutable() &&
+                        (!(fparam->storageClass & STCref) ||
+                         (fparam->storageClass & STCauto) && !farg->isLvalue()))
+                    {
+                        tt = tt->mutableOf();
+                    }
+                    declaredTuple->objects[i] = tt;
+                }
+                declareParameter(paramscope, tp, declaredTuple);
+            }
+            else
+            {
+                // Bugzilla 6810: If declared tuple is not a type tuple,
+                // it cannot be function parameter types.
+                for (size_t i = 0; i < declaredTuple->objects.dim; i++)
+                {
+                    if (!isType(declaredTuple->objects[i]))
+                        goto Lnomatch;
+                }
+            }
+            assert(declaredTuple);
+            argi += declaredTuple->objects.dim;
+            continue;
+        }
+
+        // If parameter type doesn't depend on inferred template parameters,
+        // semantic it to get actual type.
+        if (!reliesOnTident(prmtype, parameters, inferStart))
+        {
+            // should copy prmtype to avoid affecting semantic result
+            prmtype = prmtype->syntaxCopy()->semantic(fd->loc, paramscope);
+
+            if (prmtype->ty == Ttuple)
+            {
+                TypeTuple *tt = (TypeTuple *)prmtype;
+                size_t tt_dim = tt->arguments->dim;
+                for (size_t j = 0; j < tt_dim; j++, ++argi)
+                {
+                    Parameter *p = (*tt->arguments)[j];
+                    if (j == tt_dim - 1 && fvarargs == 2 && parami + 1 == nfparams && argi < nfargs)
+                    {
+                        prmtype = p->type;
+                        goto Lvarargs;
+                    }
+                    if (argi >= nfargs)
+                    {
+                        if (p->defaultArg)
+                            continue;
+                        goto Lnomatch;
+                    }
+                    farg = (*fargs)[argi];
+                    if (!farg->implicitConvTo(p->type))
+                        goto Lnomatch;
+                }
+                continue;
+            }
+        }
+
+        if (argi >= nfargs)                // if not enough arguments
+        {
+            if (!fparam->defaultArg)
+                goto Lvarargs;
+
+            /* Bugzilla 2803: Before the starting of type deduction from the function
+             * default arguments, set the already deduced parameters into paramscope.
+             * It's necessary to avoid breaking existing acceptable code. Cases:
+             *
+             * 1. Already deduced template parameters can appear in fparam->defaultArg:
+             *  auto foo(A, B)(A a, B b = A.stringof);
+             *  foo(1);
+             *  // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int'
+             *
+             * 2. If prmtype depends on default-specified template parameter, the
+             * default type should be preferred.
+             *  auto foo(N = size_t, R)(R r, N start = 0)
+             *  foo([1,2,3]);
+             *  // at fparam `N start = 0`, N should be 'size_t' before
+             *  // the deduction result from fparam->defaultArg.
+             */
+            if (argi == nfargs)
+            {
+                for (size_t i = 0; i < dedtypes->dim; i++)
+                {
+                    Type *at = isType((*dedtypes)[i]);
+                    if (at && at->ty == Tnone)
+                    {
+                        TypeDeduced *xt = (TypeDeduced *)at;
+                        (*dedtypes)[i] = xt->tded;  // 'unbox'
+                        delete xt;
+                    }
+                }
+                for (size_t i = ntargs; i < dedargs->dim; i++)
+                {
+                    TemplateParameter *tparam = (*parameters)[i];
+
+                    RootObject *oarg = (*dedargs)[i];
+                    RootObject *oded = (*dedtypes)[i];
+                    if (!oarg)
+                    {
+                        if (oded)
+                        {
+                            if (tparam->specialization() || !tparam->isTemplateTypeParameter())
+                            {
+                                /* The specialization can work as long as afterwards
+                                 * the oded == oarg
+                                 */
+                                (*dedargs)[i] = oded;
+                                MATCH m2 = tparam->matchArg(loc, paramscope, dedargs, i, parameters, dedtypes, NULL);
+                                //printf("m2 = %d\n", m2);
+                                if (m2 <= MATCHnomatch)
+                                    goto Lnomatch;
+                                if (m2 < matchTiargs)
+                                    matchTiargs = m2;             // pick worst match
+                                if (!(*dedtypes)[i]->equals(oded))
+                                    error("specialization not allowed for deduced parameter %s", tparam->ident->toChars());
+                            }
+                            else
+                            {
+                                if (MATCHconvert < matchTiargs)
+                                    matchTiargs = MATCHconvert;
+                            }
+                            (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
+                        }
+                        else
+                        {
+                            oded = tparam->defaultArg(loc, paramscope);
+                            if (oded)
+                                (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
+                        }
+                    }
+                }
+            }
+            nfargs2 = argi + 1;
+
+            /* If prmtype does not depend on any template parameters:
+             *
+             *  auto foo(T)(T v, double x = 0);
+             *  foo("str");
+             *  // at fparam == 'double x = 0'
+             *
+             * or, if all template parameters in the prmtype are already deduced:
+             *
+             *  auto foo(R)(R range, ElementType!R sum = 0);
+             *  foo([1,2,3]);
+             *  // at fparam == 'ElementType!R sum = 0'
+             *
+             * Deducing prmtype from fparam->defaultArg is not necessary.
+             */
+            if (prmtype->deco ||
+                prmtype->syntaxCopy()->trySemantic(loc, paramscope))
+            {
+                ++argi;
+                continue;
+            }
+
+            // Deduce prmtype from the defaultArg.
+            farg = fparam->defaultArg->syntaxCopy();
+            farg = ::semantic(farg, paramscope);
+            farg = resolveProperties(paramscope, farg);
+        }
+        else
+        {
+            farg = (*fargs)[argi];
+        }
+        {
+            // Check invalid arguments to detect errors early.
+            if (farg->op == TOKerror || farg->type->ty == Terror)
+                goto Lnomatch;
+
+Lretry:
+#if 0
+            printf("\tfarg->type   = %s\n", farg->type->toChars());
+            printf("\tfparam->type = %s\n", prmtype->toChars());
+#endif
+            Type *argtype = farg->type;
+
+            if (!(fparam->storageClass & STClazy) && argtype->ty == Tvoid && farg->op != TOKfunction)
+                goto Lnomatch;
+
+            // Bugzilla 12876: optimize arugument to allow CT-known length matching
+            farg = farg->optimize(WANTvalue, (fparam->storageClass & (STCref | STCout)) != 0);
+            //printf("farg = %s %s\n", farg->type->toChars(), farg->toChars());
+
+            RootObject *oarg = farg;
+            if ((fparam->storageClass & STCref) &&
+                (!(fparam->storageClass & STCauto) || farg->isLvalue()))
+            {
+                /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
+                 */
+                Type *taai;
+                if ( argtype->ty == Tarray &&
+                    (prmtype->ty == Tsarray ||
+                     prmtype->ty == Taarray && (taai = ((TypeAArray *)prmtype)->index)->ty == Tident &&
+                                               ((TypeIdentifier *)taai)->idents.dim == 0))
+                {
+                    if (farg->op == TOKstring)
+                    {
+                        StringExp *se = (StringExp *)farg;
+                        argtype = se->type->nextOf()->sarrayOf(se->len);
+                    }
+                    else if (farg->op == TOKarrayliteral)
+                    {
+                        ArrayLiteralExp *ae = (ArrayLiteralExp *)farg;
+                        argtype = ae->type->nextOf()->sarrayOf(ae->elements->dim);
+                    }
+                    else if (farg->op == TOKslice)
+                    {
+                        SliceExp *se = (SliceExp *)farg;
+                        if (Type *tsa = toStaticArrayType(se))
+                            argtype = tsa;
+                    }
+                }
+
+                oarg = argtype;
+            }
+            else if ((fparam->storageClass & STCout) == 0 &&
+                     (argtype->ty == Tarray || argtype->ty == Tpointer) &&
+                     templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND &&
+                     ((TypeIdentifier *)prmtype)->idents.dim == 0)
+            {
+                /* The farg passing to the prmtype always make a copy. Therefore,
+                 * we can shrink the set of the deduced type arguments for prmtype
+                 * by adjusting top-qualifier of the argtype.
+                 *
+                 *  prmtype         argtype     ta
+                 *  T            <- const(E)[]  const(E)[]
+                 *  T            <- const(E[])  const(E)[]
+                 *  qualifier(T) <- const(E)[]  const(E[])
+                 *  qualifier(T) <- const(E[])  const(E[])
+                 */
+                Type *ta = argtype->castMod(prmtype->mod ? argtype->nextOf()->mod : 0);
+                if (ta != argtype)
+                {
+                    Expression *ea = farg->copy();
+                    ea->type = ta;
+                    oarg = ea;
+                }
+            }
+
+            if (fvarargs == 2 && parami + 1 == nfparams && argi + 1 < nfargs)
+                goto Lvarargs;
+
+            unsigned wm = 0;
+            MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &wm, inferStart);
+            //printf("\tL%d deduceType m = %d, wm = x%x, wildmatch = x%x\n", __LINE__, m, wm, wildmatch);
+            wildmatch |= wm;
+
+            /* If no match, see if the argument can be matched by using
+             * implicit conversions.
+             */
+            if (m == MATCHnomatch && prmtype->deco)
+                m = farg->implicitConvTo(prmtype);
+
+            if (m == MATCHnomatch)
+            {
+                AggregateDeclaration *ad = isAggregate(farg->type);
+                if (ad && ad->aliasthis)
+                {
+                    /* If a semantic error occurs while doing alias this,
+                     * eg purity(bug 7295), just regard it as not a match.
+                     */
+                    unsigned olderrors = global.startGagging();
+                    Expression *e = resolveAliasThis(sc, farg);
+                    if (!global.endGagging(olderrors))
+                    {
+                        farg = e;
+                        goto Lretry;
+                    }
+                }
+            }
+
+            if (m > MATCHnomatch && (fparam->storageClass & (STCref | STCauto)) == STCref)
+            {
+                if (!farg->isLvalue())
+                {
+                    if ((farg->op == TOKstring || farg->op == TOKslice) &&
+                        (prmtype->ty == Tsarray || prmtype->ty == Taarray))
+                    {
+                        // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
+                    }
+                    else
+                        goto Lnomatch;
+                }
+            }
+            if (m > MATCHnomatch && (fparam->storageClass & STCout))
+            {
+                if (!farg->isLvalue())
+                    goto Lnomatch;
+                if (!farg->type->isMutable())   // Bugzilla 11916
+                    goto Lnomatch;
+            }
+            if (m == MATCHnomatch && (fparam->storageClass & STClazy) && prmtype->ty == Tvoid &&
+                    farg->type->ty != Tvoid)
+                m = MATCHconvert;
+
+            if (m != MATCHnomatch)
+            {
+                if (m < match)
+                    match = m;          // pick worst match
+                argi++;
+                continue;
+            }
+        }
+
+    Lvarargs:
+        /* The following code for variadic arguments closely
+         * matches TypeFunction::callMatch()
+         */
+        if (!(fvarargs == 2 && parami + 1 == nfparams))
+            goto Lnomatch;
+
+        /* Check for match with function parameter T...
+         */
+        Type *tb = prmtype->toBasetype();
+        switch (tb->ty)
+        {
+            // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
+            case Tsarray:
+            case Taarray:
+            {
+                // Perhaps we can do better with this, see TypeFunction::callMatch()
+                if (tb->ty == Tsarray)
+                {
+                    TypeSArray *tsa = (TypeSArray *)tb;
+                    dinteger_t sz = tsa->dim->toInteger();
+                    if (sz != nfargs - argi)
+                        goto Lnomatch;
+                }
+                else if (tb->ty == Taarray)
+                {
+                    TypeAArray *taa = (TypeAArray *)tb;
+                    Expression *dim = new IntegerExp(instLoc, nfargs - argi, Type::tsize_t);
+
+                    size_t i = templateParameterLookup(taa->index, parameters);
+                    if (i == IDX_NOTFOUND)
+                    {
+                        Expression *e;
+                        Type *t;
+                        Dsymbol *s;
+                        taa->index->resolve(instLoc, sc, &e, &t, &s);
+                        if (!e)
+                            goto Lnomatch;
+                        e = e->ctfeInterpret();
+                        e = e->implicitCastTo(sc, Type::tsize_t);
+                        e = e->optimize(WANTvalue);
+                        if (!dim->equals(e))
+                            goto Lnomatch;
+                    }
+                    else
+                    {
+                        // This code matches code in TypeInstance::deduceType()
+                        TemplateParameter *tprm = (*parameters)[i];
+                        TemplateValueParameter *tvp = tprm->isTemplateValueParameter();
+                        if (!tvp)
+                            goto Lnomatch;
+                        Expression *e = (Expression *)(*dedtypes)[i];
+                        if (e)
+                        {
+                            if (!dim->equals(e))
+                                goto Lnomatch;
+                        }
+                        else
+                        {
+                            Type *vt = tvp->valType->semantic(Loc(), sc);
+                            MATCH m = (MATCH)dim->implicitConvTo(vt);
+                            if (m <= MATCHnomatch)
+                                goto Lnomatch;
+                            (*dedtypes)[i] = dim;
+                        }
+                    }
+                }
+                /* fall through */
+            }
+            case Tarray:
+            {
+                TypeArray *ta = (TypeArray *)tb;
+                Type *tret = fparam->isLazyArray();
+                for (; argi < nfargs; argi++)
+                {
+                    Expression *arg = (*fargs)[argi];
+                    assert(arg);
+
+                    MATCH m;
+                    /* If lazy array of delegates,
+                     * convert arg(s) to delegate(s)
+                     */
+                    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
+                    {
+                        unsigned wm = 0;
+                        m = deduceType(arg, paramscope, ta->next, parameters, dedtypes, &wm, inferStart);
+                        wildmatch |= wm;
+                    }
+                    if (m == MATCHnomatch)
+                        goto Lnomatch;
+                    if (m < match)
+                        match = m;
+                }
+                goto Lmatch;
+            }
+            case Tclass:
+            case Tident:
+                goto Lmatch;
+
+            default:
+                goto Lnomatch;
+        }
+        ++argi;
+    }
+    //printf("-> argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
+    if (argi != nfargs2 && !fvarargs)
+        goto Lnomatch;
+    }
+
+Lmatch:
+
+    for (size_t i = 0; i < dedtypes->dim; i++)
+    {
+        Type *at = isType((*dedtypes)[i]);
+        if (at)
+        {
+            if (at->ty == Tnone)
+            {
+                TypeDeduced *xt = (TypeDeduced *)at;
+                at = xt->tded;  // 'unbox'
+                delete xt;
+            }
+            (*dedtypes)[i] = at->merge2();
+        }
+    }
+    for (size_t i = ntargs; i < dedargs->dim; i++)
+    {
+        TemplateParameter *tparam = (*parameters)[i];
+        //printf("tparam[%d] = %s\n", i, tparam->ident->toChars());
+        /* For T:T*, the dedargs is the T*, dedtypes is the T
+         * But for function templates, we really need them to match
+         */
+        RootObject *oarg = (*dedargs)[i];
+        RootObject *oded = (*dedtypes)[i];
+        //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
+        //if (oarg) printf("oarg: %s\n", oarg->toChars());
+        //if (oded) printf("oded: %s\n", oded->toChars());
+        if (!oarg)
+        {
+            if (oded)
+            {
+                if (tparam->specialization() || !tparam->isTemplateTypeParameter())
+                {
+                    /* The specialization can work as long as afterwards
+                     * the oded == oarg
+                     */
+                    (*dedargs)[i] = oded;
+                    MATCH m2 = tparam->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, NULL);
+                    //printf("m2 = %d\n", m2);
+                    if (m2 <= MATCHnomatch)
+                        goto Lnomatch;
+                    if (m2 < matchTiargs)
+                        matchTiargs = m2;             // pick worst match
+                    if (!(*dedtypes)[i]->equals(oded))
+                        error("specialization not allowed for deduced parameter %s", tparam->ident->toChars());
+                }
+                else
+                {
+                    if (MATCHconvert < matchTiargs)
+                        matchTiargs = MATCHconvert;
+                }
+            }
+            else
+            {
+                oded = tparam->defaultArg(instLoc, paramscope);
+                if (!oded)
+                {
+                    // if tuple parameter and
+                    // tuple parameter was not in function parameter list and
+                    // we're one or more arguments short (i.e. no tuple argument)
+                    if (tparam == tp &&
+                        fptupindex == IDX_NOTFOUND &&
+                        ntargs <= dedargs->dim - 1)
+                    {
+                        // make tuple argument an empty tuple
+                        oded = (RootObject *)new Tuple();
+                    }
+                    else
+                        goto Lnomatch;
+                }
+                if (isError(oded))
+                    goto Lerror;
+                ntargs++;
+
+                /* At the template parameter T, the picked default template argument
+                 * X!int should be matched to T in order to deduce dependent
+                 * template parameter A.
+                 *  auto foo(T : X!A = X!int, A...)() { ... }
+                 *  foo();  // T <-- X!int, A <-- (int)
+                 */
+                if (tparam->specialization())
+                {
+                    (*dedargs)[i] = oded;
+                    MATCH m2 = tparam->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, NULL);
+                    //printf("m2 = %d\n", m2);
+                    if (m2 <= MATCHnomatch)
+                        goto Lnomatch;
+                    if (m2 < matchTiargs)
+                        matchTiargs = m2;             // pick worst match
+                    if (!(*dedtypes)[i]->equals(oded))
+                        error("specialization not allowed for deduced parameter %s", tparam->ident->toChars());
+                }
+            }
+            oded = declareParameter(paramscope, tparam, oded);
+            (*dedargs)[i] = oded;
+        }
+    }
+
+    /* Bugzilla 7469: As same as the code for 7469 in findBestMatch,
+     * expand a Tuple in dedargs to normalize template arguments.
+     */
+    if (size_t d = dedargs->dim)
+    {
+        if (Tuple *va = isTuple((*dedargs)[d - 1]))
+        {
+            if (va->objects.dim)
+            {
+                dedargs->setDim(d - 1);
+                dedargs->insert(d - 1, &va->objects);
+            }
+        }
+    }
+    ti->tiargs = dedargs; // update to the normalized template arguments.
+
+    // Partially instantiate function for constraint and fd->leastAsSpecialized()
+    {
+        assert(paramsym);
+        Scope *sc2 = _scope;
+        sc2 = sc2->push(paramsym);
+        sc2 = sc2->push(ti);
+        sc2->parent = ti;
+        sc2->tinst = ti;
+        sc2->minst = sc->minst;
+
+        fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs);
+
+        sc2 = sc2->pop();
+        sc2 = sc2->pop();
+
+        if (!fd)
+            goto Lnomatch;
+    }
+
+    if (constraint)
+    {
+        if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd))
+            goto Lnomatch;
+    }
+
+#if 0
+    for (size_t i = 0; i < dedargs->dim; i++)
+    {
+        RootObject *o = (*dedargs)[i];
+        printf("\tdedargs[%d] = %d, %s\n", i, o->dyncast(), o->toChars());
+    }
+#endif
+
+    paramscope->pop();
+    //printf("\tmatch %d\n", match);
+    return (MATCH)(match | (matchTiargs<<4));
+
+Lnomatch:
+    paramscope->pop();
+    //printf("\tnomatch\n");
+    return MATCHnomatch;
+
+Lerror: // todo: for the future improvement
+    paramscope->pop();
+    //printf("\terror\n");
+    return MATCHnomatch;
+}
+
+/**************************************************
+ * Declare template parameter tp with value o, and install it in the scope sc.
+ */
+
+RootObject *TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o)
+{
+    //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o);
+
+    Type *ta = isType(o);
+    Expression *ea = isExpression(o);
+    Dsymbol *sa = isDsymbol(o);
+    Tuple *va = isTuple(o);
+
+    Declaration *d;
+    VarDeclaration *v = NULL;
+
+    if (ea && ea->op == TOKtype)
+        ta = ea->type;
+    else if (ea && ea->op == TOKscope)
+        sa = ((ScopeExp *)ea)->sds;
+    else if (ea && (ea->op == TOKthis || ea->op == TOKsuper))
+        sa = ((ThisExp *)ea)->var;
+    else if (ea && ea->op == TOKfunction)
+    {
+        if (((FuncExp *)ea)->td)
+            sa = ((FuncExp *)ea)->td;
+        else
+            sa = ((FuncExp *)ea)->fd;
+    }
+
+    if (ta)
+    {
+        //printf("type %s\n", ta->toChars());
+        d = new AliasDeclaration(Loc(), tp->ident, ta);
+    }
+    else if (sa)
+    {
+        //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars());
+        d = new AliasDeclaration(Loc(), 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;
+
+        v = new VarDeclaration(loc, t, tp->ident, init);
+        v->storage_class = STCmanifest | STCtemplateparameter;
+        d = v;
+    }
+    else if (va)
+    {
+        //printf("\ttuple\n");
+        d = new TupleDeclaration(loc, tp->ident, &va->objects);
+    }
+    else
+    {
+#ifdef DEBUG
+        o->print();
+#endif
+        assert(0);
+    }
+
+    d->storage_class |= STCtemplateparameter;
+    if (ta)
+    {
+        Type *t = ta;
+        // consistent with Type::checkDeprecated()
+        while (t->ty != Tenum)
+        {
+            if (!t->nextOf()) break;
+            t = ((TypeNext *)t)->next;
+        }
+        if (Dsymbol *s = t->toDsymbol(sc))
+        {
+            if (s->isDeprecated())
+                d->storage_class |= STCdeprecated;
+        }
+    }
+    else if (sa)
+    {
+        if (sa->isDeprecated())
+            d->storage_class |= STCdeprecated;
+    }
+
+    if (!sc->insert(d))
+        error("declaration %s is already defined", tp->ident->toChars());
+    d->semantic(sc);
+
+    /* So the caller's o gets updated with the result of semantic() being run on o
+     */
+    if (v)
+        o = initializerToExpression(v->_init);
+    return o;
+}
+
+/**************************************
+ * Determine if TemplateDeclaration is variadic.
+ */
+
+TemplateTupleParameter *isVariadic(TemplateParameters *parameters)
+{
+    size_t dim = parameters->dim;
+    TemplateTupleParameter *tp = NULL;
+
+    if (dim)
+        tp = ((*parameters)[dim - 1])->isTemplateTupleParameter();
+    return tp;
+}
+
+TemplateTupleParameter *TemplateDeclaration::isVariadic()
+{
+    return ::isVariadic(parameters);
+}
+
+/***********************************
+ * We can overload templates.
+ */
+
+bool TemplateDeclaration::isOverloadable()
+{
+    return true;
+}
+
+/*************************************************
+ * Given function arguments, figure out which template function
+ * to expand, and return matching result.
+ * Input:
+ *      m               matching result
+ *      dstart          the root of overloaded function templates
+ *      loc             instantiation location
+ *      sc              instantiation scope
+ *      tiargs          initial list of template arguments
+ *      tthis           if !NULL, the 'this' pointer argument
+ *      fargs           arguments to function
+ */
+
+void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
+        Objects *tiargs, Type *tthis, Expressions *fargs)
+{
+#if 0
+    printf("functionResolve() dstart = %s\n", dstart->toChars());
+    printf("    tiargs:\n");
+    if (tiargs)
+    {
+        for (size_t i = 0; i < tiargs->dim; i++)
+        {
+            RootObject *arg = (*tiargs)[i];
+            printf("\t%s\n", arg->toChars());
+        }
+    }
+    printf("    fargs:\n");
+    for (size_t i = 0; i < (fargs ? fargs->dim : 0); i++)
+    {
+        Expression *arg = (*fargs)[i];
+        printf("\t%s %s\n", arg->type->toChars(), arg->toChars());
+        //printf("\tty = %d\n", arg->type->ty);
+    }
+    //printf("stc = %llx\n", dstart->_scope->stc);
+    //printf("match:t/f = %d/%d\n", ta_last, m->last);
+#endif
+
+    struct ParamDeduce
+    {
+        // context
+        Loc loc;
+        Scope *sc;
+        Type *tthis;
+        Objects *tiargs;
+        Expressions *fargs;
+        // result
+        Match *m;
+        int property;       // 0: unintialized
+        // 1: seen @property
+        // 2: not @property
+        size_t ov_index;
+        TemplateDeclaration *td_best;
+        TemplateInstance *ti_best;
+        MATCH ta_last;
+        Type *tthis_best;
+
+        static int fp(void *param, Dsymbol *s)
+        {
+            if (!s->errors)
+            {
+                if (FuncDeclaration *fd = s->isFuncDeclaration())
+                    return ((ParamDeduce *)param)->applyFunction(fd);
+                if (TemplateDeclaration *td = s->isTemplateDeclaration())
+                    return ((ParamDeduce *)param)->applyTemplate(td);
+            }
+            return 0;
+        }
+
+        int applyFunction(FuncDeclaration *fd)
+        {
+            // skip duplicates
+            if (fd == m->lastf)
+                return 0;
+            // explicitly specified tiargs never match to non template function
+            if (tiargs && tiargs->dim > 0)
+                return 0;
+
+            if (fd->semanticRun == PASSinit && fd->_scope)
+            {
+                Ungag ungag = fd->ungagSpeculative();
+                fd->semantic(fd->_scope);
+            }
+            if (fd->semanticRun == PASSinit)
+            {
+                ::error(loc, "forward reference to template %s", fd->toChars());
+                return 1;
+            }
+            //printf("fd = %s %s, fargs = %s\n", fd->toChars(), fd->type->toChars(), fargs->toChars());
+            m->anyf = fd;
+            TypeFunction *tf = (TypeFunction *)fd->type;
+
+            int prop = (tf->isproperty) ? 1 : 2;
+            if (property == 0)
+                property = prop;
+            else if (property != prop)
+                error(fd->loc, "cannot overload both property and non-property functions");
+
+            /* For constructors, qualifier check will be opposite direction.
+             * Qualified constructor always makes qualified object, then will be checked
+             * that it is implicitly convertible to tthis.
+             */
+            Type *tthis_fd = fd->needThis() ? tthis : NULL;
+            if (tthis_fd && fd->isCtorDeclaration())
+            {
+                //printf("%s tf->mod = x%x tthis_fd->mod = x%x %d\n", tf->toChars(),
+                //        tf->mod, tthis_fd->mod, fd->isolateReturn());
+                if (MODimplicitConv(tf->mod, tthis_fd->mod) ||
+                    tf->isWild() && tf->isShared() == tthis_fd->isShared() ||
+                    fd->isolateReturn())
+                {
+                    /* && tf->isShared() == tthis_fd->isShared()*/
+                    // Uniquely constructed object can ignore shared qualifier.
+                    // TODO: Is this appropriate?
+                    tthis_fd = NULL;
+                }
+                else
+                    return 0;   // MATCHnomatch
+            }
+            MATCH mfa = tf->callMatch(tthis_fd, fargs);
+            //printf("test1: mfa = %d\n", mfa);
+            if (mfa > MATCHnomatch)
+            {
+                if (mfa > m->last) goto LfIsBetter;
+                if (mfa < m->last) goto LlastIsBetter;
+
+                /* See if one of the matches overrides the other.
+                */
+                assert(m->lastf);
+                if (m->lastf->overrides(fd)) goto LlastIsBetter;
+                if (fd->overrides(m->lastf)) goto LfIsBetter;
+
+                /* Try to disambiguate using template-style partial ordering rules.
+                 * In essence, if f() and g() are ambiguous, if f() can call g(),
+                 * but g() cannot call f(), then pick f().
+                 * This is because f() is "more specialized."
+                 */
+                {
+                    MATCH c1 = fd->leastAsSpecialized(m->lastf);
+                    MATCH c2 = m->lastf->leastAsSpecialized(fd);
+                    //printf("c1 = %d, c2 = %d\n", c1, c2);
+                    if (c1 > c2) goto LfIsBetter;
+                    if (c1 < c2) goto LlastIsBetter;
+                }
+
+                /* The 'overrides' check above does covariant checking only
+                 * for virtual member functions. It should do it for all functions,
+                 * but in order to not risk breaking code we put it after
+                 * the 'leastAsSpecialized' check.
+                 * In the future try moving it before.
+                 * I.e. a not-the-same-but-covariant match is preferred,
+                 * as it is more restrictive.
+                 */
+                if (!m->lastf->type->equals(fd->type))
+                {
+                    //printf("cov: %d %d\n", m->lastf->type->covariant(fd->type), fd->type->covariant(m->lastf->type));
+                    if (m->lastf->type->covariant(fd->type) == 1) goto LlastIsBetter;
+                    if (fd->type->covariant(m->lastf->type) == 1) goto LfIsBetter;
+                }
+
+                /* If the two functions are the same function, like:
+                 *    int foo(int);
+                 *    int foo(int x) { ... }
+                 * then pick the one with the body.
+                 */
+                if (tf->equals(m->lastf->type) &&
+                    fd->storage_class == m->lastf->storage_class &&
+                    fd->parent == m->lastf->parent &&
+                    fd->protection == m->lastf->protection &&
+                    fd->linkage == m->lastf->linkage)
+                {
+                    if ( fd->fbody && !m->lastf->fbody) goto LfIsBetter;
+                    if (!fd->fbody &&  m->lastf->fbody) goto LlastIsBetter;
+                }
+
+                m->nextf = fd;
+                m->count++;
+                return 0;
+
+            LlastIsBetter:
+                return 0;
+
+            LfIsBetter:
+                td_best = NULL;
+                ti_best = NULL;
+                ta_last = MATCHexact;
+                m->last = mfa;
+                m->lastf = fd;
+                tthis_best = tthis_fd;
+                ov_index = 0;
+                m->count = 1;
+                return 0;
+            }
+            return 0;
+        }
+
+        int applyTemplate(TemplateDeclaration *td)
+        {
+            //printf("applyTemplate()\n");
+            // skip duplicates
+            if (td == td_best)
+                return 0;
+
+            if (!sc)
+                sc = td->_scope; // workaround for Type::aliasthisOf
+
+            if (td->semanticRun == PASSinit && td->_scope)
+            {
+                // Try to fix forward reference. Ungag errors while doing so.
+                Ungag ungag = td->ungagSpeculative();
+                td->semantic(td->_scope);
+            }
+            if (td->semanticRun == PASSinit)
+            {
+                ::error(loc, "forward reference to template %s", td->toChars());
+            Lerror:
+                m->lastf = NULL;
+                m->count = 0;
+                m->last = MATCHnomatch;
+                return 1;
+            }
+            //printf("td = %s\n", td->toChars());
+
+            FuncDeclaration *f;
+            f = td->onemember ? td->onemember->isFuncDeclaration() : NULL;
+            if (!f)
+            {
+                if (!tiargs)
+                    tiargs = new Objects();
+                TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
+                Objects dedtypes;
+                dedtypes.setDim(td->parameters->dim);
+                assert(td->semanticRun != PASSinit);
+                MATCH mta = td->matchWithInstance(sc, ti, &dedtypes, fargs, 0);
+                //printf("matchWithInstance = %d\n", mta);
+                if (mta <= MATCHnomatch || mta < ta_last)      // no match or less match
+                    return 0;
+
+                ti->semantic(sc, fargs);
+                if (!ti->inst)                  // if template failed to expand
+                    return 0;
+
+                Dsymbol *s = ti->inst->toAlias();
+                FuncDeclaration *fd;
+                if (TemplateDeclaration *tdx = s->isTemplateDeclaration())
+                {
+                    Objects dedtypesX;  // empty tiargs
+
+                    // Bugzilla 11553: Check for recursive instantiation of tdx.
+                    for (TemplatePrevious *p = tdx->previous; p; p = p->prev)
+                    {
+                        if (arrayObjectMatch(p->dedargs, &dedtypesX))
+                        {
+                            //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars());
+                            /* It must be a subscope of p->sc, other scope chains are not recursive
+                             * instantiations.
+                             */
+                            for (Scope *scx = sc; scx; scx = scx->enclosing)
+                            {
+                                if (scx == p->sc)
+                                {
+                                    error(loc, "recursive template expansion while looking for %s.%s", ti->toChars(), tdx->toChars());
+                                    goto Lerror;
+                                }
+                            }
+                        }
+                        /* BUG: should also check for ref param differences
+                        */
+                    }
+
+                    TemplatePrevious pr;
+                    pr.prev = tdx->previous;
+                    pr.sc = sc;
+                    pr.dedargs = &dedtypesX;
+                    tdx->previous = &pr;                 // add this to threaded list
+
+                    fd = resolveFuncCall(loc, sc, s, NULL, tthis, fargs, 1);
+
+                    tdx->previous = pr.prev;             // unlink from threaded list
+                }
+                else if (s->isFuncDeclaration())
+                {
+                    fd = resolveFuncCall(loc, sc, s, NULL, tthis, fargs, 1);
+                }
+                else
+                    goto Lerror;
+
+                if (!fd)
+                    return 0;
+
+                if (fd->type->ty != Tfunction)
+                {
+                    m->lastf = fd;   // to propagate "error match"
+                    m->count = 1;
+                    m->last = MATCHnomatch;
+                    return 1;
+                }
+
+                Type *tthis_fd = fd->needThis() && !fd->isCtorDeclaration() ? tthis : NULL;
+
+                TypeFunction *tf = (TypeFunction *)fd->type;
+                MATCH mfa = tf->callMatch(tthis_fd, fargs);
+                if (mfa < m->last)
+                    return 0;
+
+                if (mta < ta_last) goto Ltd_best2;
+                if (mta > ta_last) goto Ltd2;
+
+                if (mfa < m->last) goto Ltd_best2;
+                if (mfa > m->last) goto Ltd2;
+
+            Lambig2:  // td_best and td are ambiguous
+                //printf("Lambig2\n");
+                m->nextf = fd;
+                m->count++;
+                return 0;
+
+            Ltd_best2:
+                return 0;
+
+            Ltd2:
+                // td is the new best match
+                assert(td->_scope);
+                td_best = td;
+                ti_best = NULL;
+                property = 0;   // (backward compatibility)
+                ta_last = mta;
+                m->last = mfa;
+                m->lastf = fd;
+                tthis_best = tthis_fd;
+                ov_index = 0;
+                m->nextf = NULL;
+                m->count = 1;
+                return 0;
+            }
+
+            //printf("td = %s\n", td->toChars());
+            for (size_t ovi = 0; f; f = f->overnext0, ovi++)
+            {
+                if (f->type->ty != Tfunction || f->errors)
+                    goto Lerror;
+
+                /* This is a 'dummy' instance to evaluate constraint properly.
+                */
+                TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
+                ti->parent = td->parent;    // Maybe calculating valid 'enclosing' is unnecessary.
+
+                FuncDeclaration *fd = f;
+                int x = td->deduceFunctionTemplateMatch(ti, sc, fd, tthis, fargs);
+                MATCH mta = (MATCH)(x >> 4);
+                MATCH mfa = (MATCH)(x & 0xF);
+                //printf("match:t/f = %d/%d\n", mta, mfa);
+                if (!fd || mfa == MATCHnomatch)
+                    continue;
+
+                Type *tthis_fd = fd->needThis() ? tthis : NULL;
+
+                if (fd->isCtorDeclaration())
+                {
+                    // Constructor call requires additional check.
+
+                    TypeFunction *tf = (TypeFunction *)fd->type;
+                    if (tthis_fd)
+                    {
+                        assert(tf->next);
+                        if (MODimplicitConv(tf->mod, tthis_fd->mod) ||
+                            tf->isWild() && tf->isShared() == tthis_fd->isShared() ||
+                            fd->isolateReturn())
+                        {
+                            tthis_fd = NULL;
+                        }
+                        else
+                            continue;   // MATCHnomatch
+                    }
+                }
+
+                if (mta < ta_last) goto Ltd_best;
+                if (mta > ta_last) goto Ltd;
+
+                if (mfa < m->last) goto Ltd_best;
+                if (mfa > m->last) goto Ltd;
+
+                if (td_best)
+                {
+                    // Disambiguate by picking the most specialized TemplateDeclaration
+                    MATCH c1 = td->leastAsSpecialized(sc, td_best, fargs);
+                    MATCH c2 = td_best->leastAsSpecialized(sc, td, fargs);
+                    //printf("1: c1 = %d, c2 = %d\n", c1, c2);
+                    if (c1 > c2) goto Ltd;
+                    if (c1 < c2) goto Ltd_best;
+                }
+                assert(fd && m->lastf);
+                {
+                    // Disambiguate by tf->callMatch
+                    TypeFunction *tf1 = (TypeFunction *)fd->type;
+                    assert(tf1->ty == Tfunction);
+                    TypeFunction *tf2 = (TypeFunction *)m->lastf->type;
+                    assert(tf2->ty == Tfunction);
+                    MATCH c1 = tf1->callMatch(tthis_fd,   fargs);
+                    MATCH c2 = tf2->callMatch(tthis_best, fargs);
+                    //printf("2: c1 = %d, c2 = %d\n", c1, c2);
+                    if (c1 > c2) goto Ltd;
+                    if (c1 < c2) goto Ltd_best;
+                }
+                {
+                    // Disambiguate by picking the most specialized FunctionDeclaration
+                    MATCH c1 = fd->leastAsSpecialized(m->lastf);
+                    MATCH c2 = m->lastf->leastAsSpecialized(fd);
+                    //printf("3: c1 = %d, c2 = %d\n", c1, c2);
+                    if (c1 > c2) goto Ltd;
+                    if (c1 < c2) goto Ltd_best;
+                }
+
+                m->nextf = fd;
+                m->count++;
+                continue;
+
+            Ltd_best:         // td_best is the best match so far
+                //printf("Ltd_best\n");
+                continue;
+
+            Ltd:              // td is the new best match
+                //printf("Ltd\n");
+                assert(td->_scope);
+                td_best = td;
+                ti_best = ti;
+                property = 0;   // (backward compatibility)
+                ta_last = mta;
+                m->last = mfa;
+                m->lastf = fd;
+                tthis_best = tthis_fd;
+                ov_index = ovi;
+                m->nextf = NULL;
+                m->count = 1;
+                continue;
+            }
+            return 0;
+        }
+    };
+    ParamDeduce p;
+    // context
+    p.loc    = loc;
+    p.sc     = sc;
+    p.tthis  = tthis;
+    p.tiargs = tiargs;
+    p.fargs  = fargs;
+
+    // result
+    p.m          = m;
+    p.property   = 0;
+    p.ov_index   = 0;
+    p.td_best    = NULL;
+    p.ti_best    = NULL;
+    p.ta_last    = m->last != MATCHnomatch ? MATCHexact : MATCHnomatch;
+    p.tthis_best = NULL;
+
+    TemplateDeclaration *td = dstart->isTemplateDeclaration();
+    if (td && td->funcroot)
+        dstart = td->funcroot;
+
+    overloadApply(dstart, &p, &ParamDeduce::fp);
+
+    //printf("td_best = %p, m->lastf = %p\n", p.td_best, m->lastf);
+    if (p.td_best && p.ti_best && m->count == 1)
+    {
+        // Matches to template function
+        assert(p.td_best->onemember && p.td_best->onemember->isFuncDeclaration());
+
+        /* The best match is td_best with arguments tdargs.
+         * Now instantiate the template.
+         */
+        assert(p.td_best->_scope);
+        if (!sc) sc = p.td_best->_scope; // workaround for Type::aliasthisOf
+
+        TemplateInstance *ti = new TemplateInstance(loc, p.td_best, p.ti_best->tiargs);
+        ti->semantic(sc, fargs);
+
+        m->lastf = ti->toAlias()->isFuncDeclaration();
+        if (!m->lastf)
+            goto Lnomatch;
+        if (ti->errors)
+        {
+        Lerror:
+            m->count = 1;
+            assert(m->lastf);
+            m->last = MATCHnomatch;
+            return;
+        }
+
+        // look forward instantiated overload function
+        // Dsymbol::oneMembers is alredy called in TemplateInstance::semantic.
+        // it has filled overnext0d
+        while (p.ov_index--)
+        {
+            m->lastf = m->lastf->overnext0;
+            assert(m->lastf);
+        }
+
+        p.tthis_best = m->lastf->needThis() && !m->lastf->isCtorDeclaration() ? tthis : NULL;
+
+        TypeFunction *tf = (TypeFunction *)m->lastf->type;
+        if (tf->ty == Terror)
+            goto Lerror;
+        assert(tf->ty == Tfunction);
+        if (!tf->callMatch(p.tthis_best, fargs))
+            goto Lnomatch;
+
+        /* As Bugzilla 3682 shows, a template instance can be matched while instantiating
+         * that same template. Thus, the function type can be incomplete. Complete it.
+         *
+         * Bugzilla 9208: For auto function, completion should be deferred to the end of
+         * its semantic3. Should not complete it in here.
+         */
+        if (tf->next && !m->lastf->inferRetType)
+        {
+            m->lastf->type = tf->semantic(loc, sc);
+        }
+    }
+    else if (m->lastf)
+    {
+        // Matches to non template function,
+        // or found matches were ambiguous.
+        assert(m->count >= 1);
+    }
+    else
+    {
+    Lnomatch:
+        m->count = 0;
+        m->lastf = NULL;
+        m->last = MATCHnomatch;
+    }
+}
+
+/*************************************************
+ * Limited function template instantiation for using fd->leastAsSpecialized()
+ */
+FuncDeclaration *TemplateDeclaration::doHeaderInstantiation(
+        TemplateInstance *ti, Scope *sc2,
+        FuncDeclaration *fd, Type *tthis, Expressions *fargs)
+{
+    assert(fd);
+#if 0
+    printf("doHeaderInstantiation this = %s\n", toChars());
+#endif
+
+    // function body and contracts are not need
+    if (fd->isCtorDeclaration())
+        fd = new CtorDeclaration(fd->loc, fd->endloc, fd->storage_class, fd->type->syntaxCopy());
+    else
+        fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, fd->type->syntaxCopy());
+    fd->parent = ti;
+
+    assert(fd->type->ty == Tfunction);
+    TypeFunction *tf = (TypeFunction *)fd->type;
+    tf->fargs = fargs;
+
+    if (tthis)
+    {
+        // Match 'tthis' to any TemplateThisParameter's
+        bool hasttp = false;
+        for (size_t i = 0; i < parameters->dim; i++)
+        {
+            TemplateParameter *tp = (*parameters)[i];
+            TemplateThisParameter *ttp = tp->isTemplateThisParameter();
+            if (ttp)
+                hasttp = true;
+        }
+        if (hasttp)
+        {
+            tf = (TypeFunction *)tf->addSTC(ModToStc(tthis->mod));
+            assert(!tf->deco);
+        }
+    }
+
+    Scope *scx = sc2->push();
+
+    // Shouldn't run semantic on default arguments and return type.
+    for (size_t i = 0; i < tf->parameters->dim; i++)
+        (*tf->parameters)[i]->defaultArg = NULL;
+    if (fd->isCtorDeclaration())
+    {
+        // For constructors, emitting return type is necessary for
+        // isolateReturn() in functionResolve.
+        scx->flags |= SCOPEctor;
+
+        Dsymbol *parent = toParent2();
+        Type *tret;
+        AggregateDeclaration *ad = parent->isAggregateDeclaration();
+        if (!ad || parent->isUnionDeclaration())
+        {
+            tret = Type::tvoid;
+        }
+        else
+        {
+            tret = ad->handleType();
+            assert(tret);
+            tret = tret->addStorageClass(fd->storage_class | scx->stc);
+            tret = tret->addMod(tf->mod);
+        }
+        tf->next = tret;
+        if (ad && ad->isStructDeclaration())
+            tf->isref = 1;
+        //printf("tf = %s\n", tf->toChars());
+    }
+    else
+        tf->next = NULL;
+    fd->type = tf;
+    fd->type = fd->type->addSTC(scx->stc);
+    fd->type = fd->type->semantic(fd->loc, scx);
+    scx = scx->pop();
+
+    if (fd->type->ty != Tfunction)
+        return NULL;
+
+    fd->originalType = fd->type;    // for mangling
+    //printf("\t[%s] fd->type = %s, mod = %x, ", loc.toChars(), fd->type->toChars(), fd->type->mod);
+    //printf("fd->needThis() = %d\n", fd->needThis());
+
+    return fd;
+}
+
+bool TemplateDeclaration::hasStaticCtorOrDtor()
+{
+    return false;               // don't scan uninstantiated templates
+}
+
+const char *TemplateDeclaration::toChars()
+{
+    if (literal)
+        return Dsymbol::toChars();
+
+    OutBuffer buf;
+    HdrGenState hgs;
+
+    buf.writestring(ident->toChars());
+    buf.writeByte('(');
+    for (size_t i = 0; i < parameters->dim; i++)
+    {
+        TemplateParameter *tp = (*parameters)[i];
+        if (i)
+            buf.writestring(", ");
+        ::toCBuffer(tp, &buf, &hgs);
+    }
+    buf.writeByte(')');
+
+    if (onemember)
+    {
+        FuncDeclaration *fd = onemember->isFuncDeclaration();
+        if (fd && fd->type)
+        {
+            TypeFunction *tf = (TypeFunction *)fd->type;
+            buf.writestring(parametersTypeToChars(tf->parameters, tf->varargs));
+        }
+    }
+
+    if (constraint)
+    {
+        buf.writestring(" if (");
+        ::toCBuffer(constraint, &buf, &hgs);
+        buf.writeByte(')');
+    }
+    return buf.extractString();
+}
+
+Prot TemplateDeclaration::prot()
+{
+    return protection;
+}
+
+/****************************************************
+ * Given a new instance tithis of this TemplateDeclaration,
+ * see if there already exists an instance.
+ * If so, return that existing instance.
+ */
+
+TemplateInstance *TemplateDeclaration::findExistingInstance(TemplateInstance *tithis, Expressions *fargs)
+{
+    //printf("findExistingInstance(%p)\n", tithis);
+    tithis->fargs = fargs;
+    TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)instances, (void *)tithis->toHash());
+    if (tinstances)
+    {
+        for (size_t i = 0; i < tinstances->dim; i++)
+        {
+            TemplateInstance *ti = (*tinstances)[i];
+            if (tithis->compare(ti) == 0)
+                return ti;
+        }
+    }
+    return NULL;
+}
+
+/********************************************
+ * Add instance ti to TemplateDeclaration's table of instances.
+ * Return a handle we can use to later remove it if it fails instantiation.
+ */
+
+TemplateInstance *TemplateDeclaration::addInstance(TemplateInstance *ti)
+{
+    //printf("addInstance() %p %p\n", instances, ti);
+    TemplateInstances **ptinstances = (TemplateInstances **)dmd_aaGet((AA **)&instances, (void *)ti->toHash());
+    if (!*ptinstances)
+        *ptinstances = new TemplateInstances();
+    (*ptinstances)->push(ti);
+    return ti;
+}
+
+/*******************************************
+ * Remove TemplateInstance from table of instances.
+ * Input:
+ *      handle returned by addInstance()
+ */
+
+void TemplateDeclaration::removeInstance(TemplateInstance *handle)
+{
+    //printf("removeInstance()\n");
+    TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)instances, (void *)handle->toHash());
+    if (tinstances)
+    {
+        for (size_t i = 0; i < tinstances->dim; i++)
+        {
+            TemplateInstance *ti = (*tinstances)[i];
+            if (handle == ti)
+            {
+                tinstances->remove(i);
+                break;
+            }
+        }
+    }
+}
+
+/* ======================== Type ============================================ */
+
+/****
+ * Given an identifier, figure out which TemplateParameter it is.
+ * Return IDX_NOTFOUND if not found.
+ */
+
+static size_t templateIdentifierLookup(Identifier *id, TemplateParameters *parameters)
+{
+    for (size_t i = 0; i < parameters->dim; i++)
+    {
+        TemplateParameter *tp = (*parameters)[i];
+        if (tp->ident->equals(id))
+            return i;
+    }
+    return IDX_NOTFOUND;
+}
+
+size_t templateParameterLookup(Type *tparam, TemplateParameters *parameters)
+{
+    if (tparam->ty == Tident)
+    {
+        TypeIdentifier *tident = (TypeIdentifier *)tparam;
+        //printf("\ttident = '%s'\n", tident->toChars());
+        return templateIdentifierLookup(tident->ident, parameters);
+    }
+    return IDX_NOTFOUND;
+}
+
+unsigned char deduceWildHelper(Type *t, Type **at, Type *tparam)
+{
+    if ((tparam->mod & MODwild) == 0)
+        return 0;
+
+    *at = NULL;
+
+    #define X(U,T)  ((U) << 4) | (T)
+    switch (X(tparam->mod, t->mod))
+    {
+        case X(MODwild,                     0):
+        case X(MODwild,                     MODconst):
+        case X(MODwild,                     MODshared):
+        case X(MODwild,                     MODshared | MODconst):
+        case X(MODwild,                     MODimmutable):
+        case X(MODwildconst,                0):
+        case X(MODwildconst,                MODconst):
+        case X(MODwildconst,                MODshared):
+        case X(MODwildconst,                MODshared | MODconst):
+        case X(MODwildconst,                MODimmutable):
+        case X(MODshared | MODwild,         MODshared):
+        case X(MODshared | MODwild,         MODshared | MODconst):
+        case X(MODshared | MODwild,         MODimmutable):
+        case X(MODshared | MODwildconst,    MODshared):
+        case X(MODshared | MODwildconst,    MODshared | MODconst):
+        case X(MODshared | MODwildconst,    MODimmutable):
+        {
+            unsigned char wm = (t->mod & ~MODshared);
+            if (wm == 0)
+                wm = MODmutable;
+            unsigned char m = (t->mod & (MODconst | MODimmutable)) | (tparam->mod & t->mod & MODshared);
+            *at = t->unqualify(m);
+            return wm;
+        }
+
+        case X(MODwild,                     MODwild):
+        case X(MODwild,                     MODwildconst):
+        case X(MODwild,                     MODshared | MODwild):
+        case X(MODwild,                     MODshared | MODwildconst):
+        case X(MODwildconst,                MODwild):
+        case X(MODwildconst,                MODwildconst):
+        case X(MODwildconst,                MODshared | MODwild):
+        case X(MODwildconst,                MODshared | MODwildconst):
+        case X(MODshared | MODwild,         MODshared | MODwild):
+        case X(MODshared | MODwild,         MODshared | MODwildconst):
+        case X(MODshared | MODwildconst,    MODshared | MODwild):
+        case X(MODshared | MODwildconst,    MODshared | MODwildconst):
+        {
+            *at = t->unqualify(tparam->mod & t->mod);
+            return MODwild;
+        }
+
+        default:
+            return 0;
+    }
+    #undef X
+}
+
+MATCH deduceTypeHelper(Type *t, Type **at, Type *tparam)
+{
+    // 9*9 == 81 cases
+
+    #define X(U,T)  ((U) << 4) | (T)
+    switch (X(tparam->mod, t->mod))
+    {
+        case X(0, 0):
+        case X(0, MODconst):
+        case X(0, MODwild):
+        case X(0, MODwildconst):
+        case X(0, MODshared):
+        case X(0, MODshared | MODconst):
+        case X(0, MODshared | MODwild):
+        case X(0, MODshared | MODwildconst):
+        case X(0, MODimmutable):
+            // foo(U)                       T                       => T
+            // foo(U)                       const(T)                => const(T)
+            // foo(U)                       inout(T)                => inout(T)
+            // foo(U)                       inout(const(T))         => inout(const(T))
+            // foo(U)                       shared(T)               => shared(T)
+            // foo(U)                       shared(const(T))        => shared(const(T))
+            // foo(U)                       shared(inout(T))        => shared(inout(T))
+            // foo(U)                       shared(inout(const(T))) => shared(inout(const(T)))
+            // foo(U)                       immutable(T)            => immutable(T)
+        {
+            *at = t;
+            return MATCHexact;
+        }
+
+        case X(MODconst,                    MODconst):
+        case X(MODwild,                     MODwild):
+        case X(MODwildconst,                MODwildconst):
+        case X(MODshared,                   MODshared):
+        case X(MODshared | MODconst,        MODshared | MODconst):
+        case X(MODshared | MODwild,         MODshared | MODwild):
+        case X(MODshared | MODwildconst,    MODshared | MODwildconst):
+        case X(MODimmutable,                MODimmutable):
+            // foo(const(U))                const(T)                => T
+            // foo(inout(U))                inout(T)                => T
+            // foo(inout(const(U)))         inout(const(T))         => T
+            // foo(shared(U))               shared(T)               => T
+            // foo(shared(const(U)))        shared(const(T))        => T
+            // foo(shared(inout(U)))        shared(inout(T))        => T
+            // foo(shared(inout(const(U)))) shared(inout(const(T))) => T
+            // foo(immutable(U))            immutable(T)            => T
+        {
+            *at = t->mutableOf()->unSharedOf();
+            return MATCHexact;
+        }
+
+        case X(MODconst,                    0):
+        case X(MODconst,                    MODwild):
+        case X(MODconst,                    MODwildconst):
+        case X(MODconst,                    MODshared | MODconst):
+        case X(MODconst,                    MODshared | MODwild):
+        case X(MODconst,                    MODshared | MODwildconst):
+        case X(MODconst,                    MODimmutable):
+        case X(MODwild,                     MODshared | MODwild):
+        case X(MODwildconst,                MODshared | MODwildconst):
+        case X(MODshared | MODconst,        MODimmutable):
+            // foo(const(U))                T                       => T
+            // foo(const(U))                inout(T)                => T
+            // foo(const(U))                inout(const(T))         => T
+            // foo(const(U))                shared(const(T))        => shared(T)
+            // foo(const(U))                shared(inout(T))        => shared(T)
+            // foo(const(U))                shared(inout(const(T))) => shared(T)
+            // foo(const(U))                immutable(T)            => T
+            // foo(inout(U))                shared(inout(T))        => shared(T)
+            // foo(inout(const(U)))         shared(inout(const(T))) => shared(T)
+            // foo(shared(const(U)))        immutable(T)            => T
+        {
+            *at = t->mutableOf();
+            return MATCHconst;
+        }
+
+        case X(MODconst,                    MODshared):
+            // foo(const(U))                shared(T)               => shared(T)
+        {
+            *at = t;
+            return MATCHconst;
+        }
+
+        case X(MODshared,                   MODshared | MODconst):
+        case X(MODshared,                   MODshared | MODwild):
+        case X(MODshared,                   MODshared | MODwildconst):
+        case X(MODshared | MODconst,        MODshared):
+            // foo(shared(U))               shared(const(T))        => const(T)
+            // foo(shared(U))               shared(inout(T))        => inout(T)
+            // foo(shared(U))               shared(inout(const(T))) => inout(const(T))
+            // foo(shared(const(U)))        shared(T)               => T
+        {
+            *at = t->unSharedOf();
+            return MATCHconst;
+        }
+
+        case X(MODwildconst,                MODimmutable):
+        case X(MODshared | MODconst,        MODshared | MODwildconst):
+        case X(MODshared | MODwildconst,    MODimmutable):
+        case X(MODshared | MODwildconst,    MODshared | MODwild):
+            // foo(inout(const(U)))         immutable(T)            => T
+            // foo(shared(const(U)))        shared(inout(const(T))) => T
+            // foo(shared(inout(const(U)))) immutable(T)            => T
+            // foo(shared(inout(const(U)))) shared(inout(T))        => T
+        {
+            *at = t->unSharedOf()->mutableOf();
+            return MATCHconst;
+        }
+
+        case X(MODshared | MODconst,        MODshared | MODwild):
+            // foo(shared(const(U)))        shared(inout(T))        => T
+        {
+            *at = t->unSharedOf()->mutableOf();
+            return MATCHconst;
+        }
+
+        case X(MODwild,                     0):
+        case X(MODwild,                     MODconst):
+        case X(MODwild,                     MODwildconst):
+        case X(MODwild,                     MODimmutable):
+        case X(MODwild,                     MODshared):
+        case X(MODwild,                     MODshared | MODconst):
+        case X(MODwild,                     MODshared | MODwildconst):
+        case X(MODwildconst,                0):
+        case X(MODwildconst,                MODconst):
+        case X(MODwildconst,                MODwild):
+        case X(MODwildconst,                MODshared):
+        case X(MODwildconst,                MODshared | MODconst):
+        case X(MODwildconst,                MODshared | MODwild):
+        case X(MODshared,                   0):
+        case X(MODshared,                   MODconst):
+        case X(MODshared,                   MODwild):
+        case X(MODshared,                   MODwildconst):
+        case X(MODshared,                   MODimmutable):
+        case X(MODshared | MODconst,        0):
+        case X(MODshared | MODconst,        MODconst):
+        case X(MODshared | MODconst,        MODwild):
+        case X(MODshared | MODconst,        MODwildconst):
+        case X(MODshared | MODwild,         0):
+        case X(MODshared | MODwild,         MODconst):
+        case X(MODshared | MODwild,         MODwild):
+        case X(MODshared | MODwild,         MODwildconst):
+        case X(MODshared | MODwild,         MODimmutable):
+        case X(MODshared | MODwild,         MODshared):
+        case X(MODshared | MODwild,         MODshared | MODconst):
+        case X(MODshared | MODwild,         MODshared | MODwildconst):
+        case X(MODshared | MODwildconst,    0):
+        case X(MODshared | MODwildconst,    MODconst):
+        case X(MODshared | MODwildconst,    MODwild):
+        case X(MODshared | MODwildconst,    MODwildconst):
+        case X(MODshared | MODwildconst,    MODshared):
+        case X(MODshared | MODwildconst,    MODshared | MODconst):
+        case X(MODimmutable,                0):
+        case X(MODimmutable,                MODconst):
+        case X(MODimmutable,                MODwild):
+        case X(MODimmutable,                MODwildconst):
+        case X(MODimmutable,                MODshared):
+        case X(MODimmutable,                MODshared | MODconst):
+        case X(MODimmutable,                MODshared | MODwild):
+        case X(MODimmutable,                MODshared | MODwildconst):
+            // foo(inout(U))                T                       => nomatch
+            // foo(inout(U))                const(T)                => nomatch
+            // foo(inout(U))                inout(const(T))         => nomatch
+            // foo(inout(U))                immutable(T)            => nomatch
+            // foo(inout(U))                shared(T)               => nomatch
+            // foo(inout(U))                shared(const(T))        => nomatch
+            // foo(inout(U))                shared(inout(const(T))) => nomatch
+            // foo(inout(const(U)))         T                       => nomatch
+            // foo(inout(const(U)))         const(T)                => nomatch
+            // foo(inout(const(U)))         inout(T)                => nomatch
+            // foo(inout(const(U)))         shared(T)               => nomatch
+            // foo(inout(const(U)))         shared(const(T))        => nomatch
+            // foo(inout(const(U)))         shared(inout(T))        => nomatch
+            // foo(shared(U))               T                       => nomatch
+            // foo(shared(U))               const(T)                => nomatch
+            // foo(shared(U))               inout(T)                => nomatch
+            // foo(shared(U))               inout(const(T))         => nomatch
+            // foo(shared(U))               immutable(T)            => nomatch
+            // foo(shared(const(U)))        T                       => nomatch
+            // foo(shared(const(U)))        const(T)                => nomatch
+            // foo(shared(const(U)))        inout(T)                => nomatch
+            // foo(shared(const(U)))        inout(const(T))         => nomatch
+            // foo(shared(inout(U)))        T                       => nomatch
+            // foo(shared(inout(U)))        const(T)                => nomatch
+            // foo(shared(inout(U)))        inout(T)                => nomatch
+            // foo(shared(inout(U)))        inout(const(T))         => nomatch
+            // foo(shared(inout(U)))        immutable(T)            => nomatch
+            // foo(shared(inout(U)))        shared(T)               => nomatch
+            // foo(shared(inout(U)))        shared(const(T))        => nomatch
+            // foo(shared(inout(U)))        shared(inout(const(T))) => nomatch
+            // foo(shared(inout(const(U)))) T                       => nomatch
+            // foo(shared(inout(const(U)))) const(T)                => nomatch
+            // foo(shared(inout(const(U)))) inout(T)                => nomatch
+            // foo(shared(inout(const(U)))) inout(const(T))         => nomatch
+            // foo(shared(inout(const(U)))) shared(T)               => nomatch
+            // foo(shared(inout(const(U)))) shared(const(T))        => nomatch
+            // foo(immutable(U))            T                       => nomatch
+            // foo(immutable(U))            const(T)                => nomatch
+            // foo(immutable(U))            inout(T)                => nomatch
+            // foo(immutable(U))            inout(const(T))         => nomatch
+            // foo(immutable(U))            shared(T)               => nomatch
+            // foo(immutable(U))            shared(const(T))        => nomatch
+            // foo(immutable(U))            shared(inout(T))        => nomatch
+            // foo(immutable(U))            shared(inout(const(T))) => nomatch
+            return MATCHnomatch;
+
+        default:
+            assert(0);
+            return MATCHnomatch; // silence compiler warning about missing return
+    }
+    #undef X
+}
+
+/* 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 deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *parameters,
+        Objects *dedtypes, unsigned *wm, size_t inferStart)
+{
+    class DeduceType : public Visitor
+    {
+    public:
+        Scope *sc;
+        Type *tparam;
+        TemplateParameters *parameters;
+        Objects *dedtypes;
+        unsigned *wm;
+        size_t inferStart;
+        MATCH result;
+
+        DeduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wm, size_t inferStart)
+            : sc(sc), tparam(tparam), parameters(parameters), dedtypes(dedtypes), wm(wm), inferStart(inferStart)
+        {
+            result = MATCHnomatch;
+        }
+
+        void visit(Type *t)
+        {
+        #if 0
+            printf("Type::deduceType()\n");
+            printf("\tthis   = %d, ", t->ty); t->print();
+            printf("\ttparam = %d, ", tparam->ty); tparam->print();
+        #endif
+            if (!tparam)
+                goto Lnomatch;
+
+            if (t == tparam)
+                goto Lexact;
+
+            if (tparam->ty == Tident)
+            {
+                // Determine which parameter tparam is
+                size_t i = templateParameterLookup(tparam, parameters);
+                if (i == IDX_NOTFOUND)
+                {
+                    if (!sc)
+                        goto Lnomatch;
+
+                    /* Need a loc to go with the semantic routine.
+                     */
+                    Loc loc;
+                    if (parameters->dim)
+                    {
+                        TemplateParameter *tp = (*parameters)[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);
+                    result = deduceType(t, sc, tparam, parameters, dedtypes, wm);
+                    return;
+                }
+
+                TemplateParameter *tp = (*parameters)[i];
+
+                TypeIdentifier *tident = (TypeIdentifier *)tparam;
+                if (tident->idents.dim > 0)
+                {
+                    //printf("matching %s to %s\n", tparam->toChars(), t->toChars());
+                    Dsymbol *s = t->toDsymbol(sc);
+                    for (size_t j = tident->idents.dim; j-- > 0; )
+                    {
+                        RootObject *id = tident->idents[j];
+                        if (id->dyncast() == DYNCAST_IDENTIFIER)
+                        {
+                            if (!s || !s->parent)
+                                goto Lnomatch;
+                            Dsymbol *s2 = s->parent->search(Loc(), (Identifier *)id);
+                            if (!s2)
+                                goto Lnomatch;
+                            s2 = s2->toAlias();
+                            //printf("[%d] s = %s %s, s2 = %s %s\n", j, s->kind(), s->toChars(), s2->kind(), s2->toChars());
+                            if (s != s2)
+                            {
+                                if (Type *tx = s2->getType())
+                                {
+                                    if (s != tx->toDsymbol(sc))
+                                        goto Lnomatch;
+                                }
+                                else
+                                    goto Lnomatch;
+                            }
+                            s = s->parent;
+                        }
+                        else
+                            goto Lnomatch;
+                    }
+                    //printf("[e] s = %s\n", s?s->toChars():"(null)");
+                    if (tp->isTemplateTypeParameter())
+                    {
+                        Type *tt = s->getType();
+                        if (!tt)
+                            goto Lnomatch;
+                        Type *at = (Type *)(*dedtypes)[i];
+                        if (at && at->ty == Tnone)
+                            at = ((TypeDeduced *)at)->tded;
+                        if (!at || tt->equals(at))
+                        {
+                            (*dedtypes)[i] = tt;
+                            goto Lexact;
+                        }
+                    }
+                    if (tp->isTemplateAliasParameter())
+                    {
+                        Dsymbol *s2 = (Dsymbol *)(*dedtypes)[i];
+                        if (!s2 || s == s2)
+                        {
+                            (*dedtypes)[i] = s;
+                            goto Lexact;
+                        }
+                    }
+                    goto Lnomatch;
+                }
+
+                // Found the corresponding parameter tp
+                if (!tp->isTemplateTypeParameter())
+                    goto Lnomatch;
+
+                Type *at = (Type *)(*dedtypes)[i];
+                Type *tt;
+                if (unsigned char wx = wm ? deduceWildHelper(t, &tt, tparam) : 0)
+                {
+                    // type vs (none)
+                    if (!at)
+                    {
+                        (*dedtypes)[i] = tt;
+                        *wm |= wx;
+                        result = MATCHconst;
+                        return;
+                    }
+
+                    // type vs expressions
+                    if (at->ty == Tnone)
+                    {
+                        TypeDeduced *xt = (TypeDeduced *)at;
+                        result = xt->matchAll(tt);
+                        if (result > MATCHnomatch)
+                        {
+                            (*dedtypes)[i] = tt;
+                            if (result > MATCHconst)
+                                result = MATCHconst;    // limit level for inout matches
+                        }
+                        delete xt;
+                        return;
+                    }
+
+                    // type vs type
+                    if (tt->equals(at))
+                    {
+                        (*dedtypes)[i] = tt;    // Prefer current type match
+                        goto Lconst;
+                    }
+                    if (tt->implicitConvTo(at->constOf()))
+                    {
+                        (*dedtypes)[i] = at->constOf()->mutableOf();
+                        *wm |= MODconst;
+                        goto Lconst;
+                    }
+                    if (at->implicitConvTo(tt->constOf()))
+                    {
+                        (*dedtypes)[i] = tt->constOf()->mutableOf();
+                        *wm |= MODconst;
+                        goto Lconst;
+                    }
+                    goto Lnomatch;
+                }
+                else if (MATCH m = deduceTypeHelper(t, &tt, tparam))
+                {
+                    // type vs (none)
+                    if (!at)
+                    {
+                        (*dedtypes)[i] = tt;
+                        result = m;
+                        return;
+                    }
+
+                    // type vs expressions
+                    if (at->ty == Tnone)
+                    {
+                        TypeDeduced *xt = (TypeDeduced *)at;
+                        result = xt->matchAll(tt);
+                        if (result > MATCHnomatch)
+                        {
+                            (*dedtypes)[i] = tt;
+                        }
+                        delete xt;
+                        return;
+                    }
+
+                    // type vs type
+                    if (tt->equals(at))
+                    {
+                        goto Lexact;
+                    }
+                    if (tt->ty == Tclass && at->ty == Tclass)
+                    {
+                        result = tt->implicitConvTo(at);
+                        return;
+                    }
+                    if (tt->ty == Tsarray && at->ty == Tarray &&
+                        tt->nextOf()->implicitConvTo(at->nextOf()) >= MATCHconst)
+                    {
+                        goto Lexact;
+                    }
+                }
+                goto Lnomatch;
+            }
+
+            if (tparam->ty == Ttypeof)
+            {
+                /* Need a loc to go with the semantic routine.
+                 */
+                Loc loc;
+                if (parameters->dim)
+                {
+                    TemplateParameter *tp = (*parameters)[0];
+                    loc = tp->loc;
+                }
+
+                tparam = tparam->semantic(loc, sc);
+            }
+            if (t->ty != tparam->ty)
+            {
+                if (Dsymbol *sym = t->toDsymbol(sc))
+                {
+                    if (sym->isforwardRef() && !tparam->deco)
+                        goto Lnomatch;
+                }
+
+                MATCH m = t->implicitConvTo(tparam);
+                if (m == MATCHnomatch)
+                {
+                    if (t->ty == Tclass)
+                    {
+                        TypeClass *tc = (TypeClass *)t;
+                        if (tc->sym->aliasthis && !(tc->att & RECtracingDT))
+                        {
+                            tc->att = (AliasThisRec)(tc->att | RECtracingDT);
+                            m = deduceType(t->aliasthisOf(), sc, tparam, parameters, dedtypes, wm);
+                            tc->att = (AliasThisRec)(tc->att & ~RECtracingDT);
+                        }
+                    }
+                    else if (t->ty == Tstruct)
+                    {
+                        TypeStruct *ts = (TypeStruct *)t;
+                        if (ts->sym->aliasthis && !(ts->att & RECtracingDT))
+                        {
+                            ts->att = (AliasThisRec)(ts->att | RECtracingDT);
+                            m = deduceType(t->aliasthisOf(), sc, tparam, parameters, dedtypes, wm);
+                            ts->att = (AliasThisRec)(ts->att & ~RECtracingDT);
+                        }
+                    }
+                }
+                result = m;
+                return;
+            }
+
+            if (t->nextOf())
+            {
+                if (tparam->deco && !tparam->hasWild())
+                {
+                    result = t->implicitConvTo(tparam);
+                    return;
+                }
+
+                Type *tpn = tparam->nextOf();
+                if (wm && t->ty == Taarray && tparam->isWild())
+                {
+                    // Bugzilla 12403: In IFTI, stop inout matching on transitive part of AA types.
+                    tpn = tpn->substWildTo(MODmutable);
+                }
+
+                result = deduceType(t->nextOf(), sc, tpn, parameters, dedtypes, wm);
+                return;
+            }
+
+        Lexact:
+            result = MATCHexact;
+            return;
+
+        Lnomatch:
+            result = MATCHnomatch;
+            return;
+
+        Lconst:
+            result = MATCHconst;
+        }
+
+        void visit(TypeVector *t)
+        {
+        #if 0
+            printf("TypeVector::deduceType()\n");
+            printf("\tthis   = %d, ", t->ty); t->print();
+            printf("\ttparam = %d, ", tparam->ty); tparam->print();
+        #endif
+            if (tparam->ty == Tvector)
+            {
+                TypeVector *tp = (TypeVector *)tparam;
+                result = deduceType(t->basetype, sc, tp->basetype, parameters, dedtypes, wm);
+                return;
+            }
+            visit((Type *)t);
+        }
+
+        void visit(TypeDArray *t)
+        {
+        #if 0
+            printf("TypeDArray::deduceType()\n");
+            printf("\tthis   = %d, ", t->ty); t->print();
+            printf("\ttparam = %d, ", tparam->ty); tparam->print();
+        #endif
+            visit((Type *)t);
+        }
+
+        void visit(TypeSArray *t)
+        {
+        #if 0
+            printf("TypeSArray::deduceType()\n");
+            printf("\tthis   = %d, ", t->ty); t->print();
+            printf("\ttparam = %d, ", tparam->ty); tparam->print();
+        #endif
+
+            // Extra check that array dimensions must match
+            if (tparam)
+            {
+                if (tparam->ty == Tarray)
+                {
+                    MATCH m = deduceType(t->next, sc, tparam->nextOf(), parameters, dedtypes, wm);
+                    result = (m >= MATCHconst) ? MATCHconvert : MATCHnomatch;
+                    return;
+                }
+
+                TemplateParameter *tp = NULL;
+                Expression *edim = NULL;
+                size_t i;
+                if (tparam->ty == Tsarray)
+                {
+                    TypeSArray *tsa = (TypeSArray *)tparam;
+                    if (tsa->dim->op == TOKvar &&
+                        ((VarExp *)tsa->dim)->var->storage_class & STCtemplateparameter)
+                    {
+                        Identifier *id = ((VarExp *)tsa->dim)->var->ident;
+                        i = templateIdentifierLookup(id, parameters);
+                        assert(i != IDX_NOTFOUND);
+                        tp = (*parameters)[i];
+                    }
+                    else
+                        edim = tsa->dim;
+                }
+                else if (tparam->ty == Taarray)
+                {
+                    TypeAArray *taa = (TypeAArray *)tparam;
+                    i = templateParameterLookup(taa->index, parameters);
+                    if (i != IDX_NOTFOUND)
+                        tp = (*parameters)[i];
+                    else
+                    {
+                        Expression *e;
+                        Type *tx;
+                        Dsymbol *s;
+                        taa->index->resolve(Loc(), sc, &e, &tx, &s);
+                        edim = s ? getValue(s) : getValue(e);
+                    }
+                }
+                if (tp && tp->matchArg(sc, t->dim, i, parameters, dedtypes, NULL) ||
+                    edim && edim->toInteger() == t->dim->toInteger())
+                {
+                    result = deduceType(t->next, sc, tparam->nextOf(), parameters, dedtypes, wm);
+                    return;
+                }
+            }
+            visit((Type *)t);
+            return;
+
+            result = MATCHnomatch;
+        }
+
+        void visit(TypeAArray *t)
+        {
+        #if 0
+            printf("TypeAArray::deduceType()\n");
+            printf("\tthis   = %d, ", t->ty); t->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 (!deduceType(t->index, sc, tp->index, parameters, dedtypes))
+                {
+                    result = MATCHnomatch;
+                    return;
+                }
+            }
+            visit((Type *)t);
+        }
+
+        void visit(TypeFunction *t)
+        {
+            //printf("TypeFunction::deduceType()\n");
+            //printf("\tthis   = %d, ", t->ty); t->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 (t->varargs != tp->varargs ||
+                    t->linkage != tp->linkage)
+                {
+                    result = MATCHnomatch;
+                    return;
+                }
+
+                size_t nfargs = Parameter::dim(t->parameters);
+                size_t nfparams = Parameter::dim(tp->parameters);
+
+                // bug 2579 fix: Apply function parameter storage classes to parameter types
+                for (size_t i = 0; i < nfparams; i++)
+                {
+                    Parameter *fparam = Parameter::getNth(tp->parameters, i);
+                    fparam->type = fparam->type->addStorageClass(fparam->storageClass);
+                    fparam->storageClass &= ~(STC_TYPECTOR | STCin);
+                }
+                //printf("\t-> this   = %d, ", t->ty); t->print();
+                //printf("\t-> tparam = %d, ", tparam->ty); tparam->print();
+
+                /* 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.
+                     */
+                    Parameter *fparam = Parameter::getNth(tp->parameters, nfparams - 1);
+                    assert(fparam);
+                    assert(fparam->type);
+                    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 *tx = (*parameters)[tupi];
+                        TemplateTupleParameter *tup = tx->isTemplateTupleParameter();
+                        if (tup && tup->ident->equals(tid->ident))
+                            break;
+                    }
+
+                    /* The types of the function arguments [nfparams - 1 .. nfargs]
+                     * now form the tuple argument.
+                     */
+                    size_t tuple_dim = nfargs - (nfparams - 1);
+
+                    /* See if existing tuple, and whether it matches or not
+                     */
+                    RootObject *o = (*dedtypes)[tupi];
+                    if (o)
+                    {
+                        // Existing deduced argument must be a tuple, and must match
+                        Tuple *tup = isTuple(o);
+                        if (!tup || tup->objects.dim != tuple_dim)
+                        {
+                            result = MATCHnomatch;
+                            return;
+                        }
+                        for (size_t i = 0; i < tuple_dim; i++)
+                        {
+                            Parameter *arg = Parameter::getNth(t->parameters, nfparams - 1 + i);
+                            if (!arg->type->equals(tup->objects[i]))
+                            {
+                                result = MATCHnomatch;
+                                return;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        // Create new tuple
+                        Tuple *tup = new Tuple();
+                        tup->objects.setDim(tuple_dim);
+                        for (size_t i = 0; i < tuple_dim; i++)
+                        {
+                            Parameter *arg = Parameter::getNth(t->parameters, nfparams - 1 + i);
+                            tup->objects[i] = arg->type;
+                        }
+                        (*dedtypes)[tupi] = tup;
+                    }
+                    nfparams--; // don't consider the last parameter for type deduction
+                    goto L2;
+                }
+
+            L1:
+                if (nfargs != nfparams)
+                {
+                    result = MATCHnomatch;
+                    return;
+                }
+            L2:
+                for (size_t i = 0; i < nfparams; i++)
+                {
+                    Parameter *a = Parameter::getNth(t->parameters, i);
+                    Parameter *ap = Parameter::getNth(tp->parameters, i);
+
+                    if (!a->isCovariant(t->isref, ap) ||
+                        !deduceType(a->type, sc, ap->type, parameters, dedtypes))
+                    {
+                        result = MATCHnomatch;
+                        return;
+                    }
+                }
+            }
+            visit((Type *)t);
+        }
+
+        void visit(TypeIdentifier *t)
+        {
+            // Extra check
+            if (tparam && tparam->ty == Tident)
+            {
+                TypeIdentifier *tp = (TypeIdentifier *)tparam;
+
+                for (size_t i = 0; i < t->idents.dim; i++)
+                {
+                    RootObject *id1 = t->idents[i];
+                    RootObject *id2 = tp->idents[i];
+
+                    if (!id1->equals(id2))
+                    {
+                        result = MATCHnomatch;
+                        return;
+                    }
+                }
+            }
+            visit((Type *)t);
+        }
+
+        void visit(TypeInstance *t)
+        {
+        #if 0
+            printf("TypeInstance::deduceType()\n");
+            printf("\tthis   = %d, ", t->ty); t->print();
+            printf("\ttparam = %d, ", tparam->ty); tparam->print();
+        #endif
+            // Extra check
+            if (tparam && tparam->ty == Tinstance && t->tempinst->tempdecl)
+            {
+                TemplateDeclaration *tempdecl = t->tempinst->tempdecl->isTemplateDeclaration();
+                assert(tempdecl);
+
+                TypeInstance *tp = (TypeInstance *)tparam;
+
+                //printf("tempinst->tempdecl = %p\n", tempdecl);
+                //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl);
+                if (!tp->tempinst->tempdecl)
+                {
+                    //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars());
+
+                    /* Handle case of:
+                     *  template Foo(T : sa!(T), alias sa)
+                     */
+                    size_t i = templateIdentifierLookup(tp->tempinst->name, parameters);
+                    if (i == IDX_NOTFOUND)
+                    {
+                        /* Didn't find it as a parameter identifier. Try looking
+                         * it up and seeing if is an alias. See Bugzilla 1454
+                         */
+                        TypeIdentifier *tid = new TypeIdentifier(tp->loc, tp->tempinst->name);
+                        Type *tx;
+                        Expression *e;
+                        Dsymbol *s;
+                        tid->resolve(tp->loc, sc, &e, &tx, &s);
+                        if (tx)
+                        {
+                            s = tx->toDsymbol(sc);
+                            if (TemplateInstance *ti = s ? s->parent->isTemplateInstance() : NULL)
+                            {
+                                // Bugzilla 14290: Try to match with ti->tempecl,
+                                // only when ti is an enclosing instance.
+                                Dsymbol *p = sc->parent;
+                                while (p && p != ti)
+                                    p = p->parent;
+                                if (p)
+                                    s = ti->tempdecl;
+                            }
+                        }
+                        if (s)
+                        {
+                            s = s->toAlias();
+                            TemplateDeclaration *td = s->isTemplateDeclaration();
+                            if (td)
+                            {
+                                if (td->overroot)
+                                    td = td->overroot;
+                                for (; td; td = td->overnext)
+                                {
+                                    if (td == tempdecl)
+                                        goto L2;
+                                }
+                            }
+                        }
+                        goto Lnomatch;
+                    }
+                    TemplateParameter *tpx = (*parameters)[i];
+                    if (!tpx->matchArg(sc, tempdecl, i, parameters, dedtypes, NULL))
+                        goto Lnomatch;
+                }
+                else if (tempdecl != tp->tempinst->tempdecl)
+                    goto Lnomatch;
+
+              L2:
+
+                for (size_t i = 0; 1; i++)
+                {
+                    //printf("\ttest: tempinst->tiargs[%d]\n", i);
+                    RootObject *o1 = NULL;
+                    if (i < t->tempinst->tiargs->dim)
+                        o1 = (*t->tempinst->tiargs)[i];
+                    else if (i < t->tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim)
+                    {
+                        // Pick up default arg
+                        o1 = t->tempinst->tdtypes[i];
+                    }
+                    else if (i >= tp->tempinst->tiargs->dim)
+                        break;
+
+                    if (i >= tp->tempinst->tiargs->dim)
+                    {
+                        size_t dim = tempdecl->parameters->dim - (tempdecl->isVariadic() ? 1 : 0);
+                        while (i < dim && ((*tempdecl->parameters)[i]->dependent ||
+                                           (*tempdecl->parameters)[i]->hasDefaultArg()))
+                        {
+                            i++;
+                        }
+                        if (i >= dim)
+                            break;  // match if all remained parameters are dependent
+                        goto Lnomatch;
+                    }
+
+                    RootObject *o2 = (*tp->tempinst->tiargs)[i];
+                    Type *t2 = isType(o2);
+
+                    size_t j;
+                    if (t2 &&
+                        t2->ty == Tident &&
+                        i == tp->tempinst->tiargs->dim - 1 &&
+                        (j = templateParameterLookup(t2, parameters), j != IDX_NOTFOUND) &&
+                        j == parameters->dim - 1 &&
+                        (*parameters)[j]->isTemplateTupleParameter())
+                    {
+                        /* Given:
+                         *  struct A(B...) {}
+                         *  alias A!(int, float) X;
+                         *  static if (is(X Y == A!(Z), Z...)) {}
+                         * deduce that Z is a tuple(int, float)
+                         */
+
+                        /* Create tuple from remaining args
+                         */
+                        Tuple *vt = new Tuple();
+                        size_t vtdim = (tempdecl->isVariadic()
+                                        ? t->tempinst->tiargs->dim : t->tempinst->tdtypes.dim) - i;
+                        vt->objects.setDim(vtdim);
+                        for (size_t k = 0; k < vtdim; k++)
+                        {
+                            RootObject *o;
+                            if (k < t->tempinst->tiargs->dim)
+                                o = (*t->tempinst->tiargs)[i + k];
+                            else    // Pick up default arg
+                                o = t->tempinst->tdtypes[i + k];
+                            vt->objects[k] = o;
+                        }
+
+                        Tuple *v = (Tuple *)(*dedtypes)[j];
+                        if (v)
+                        {
+                            if (!match(v, vt))
+                                goto Lnomatch;
+                        }
+                        else
+                            (*dedtypes)[j] = vt;
+                        break;
+                    }
+                    else if (!o1)
+                        break;
+
+                    Type *t1 = isType(o1);
+                    Dsymbol *s1 = isDsymbol(o1);
+                    Dsymbol *s2 = isDsymbol(o2);
+                    Expression *e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
+                    Expression *e2 = isExpression(o2);
+        #if 0
+                    Tuple *v1 = isTuple(o1);
+                    Tuple *v2 = isTuple(o2);
+                    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());
+                    if (s1)     printf("s1 = %s\n", s1->toChars());
+                    if (s2)     printf("s2 = %s\n", s2->toChars());
+                    if (v1)     printf("v1 = %s\n", v1->toChars());
+                    if (v2)     printf("v2 = %s\n", v2->toChars());
+        #endif
+
+                    if (t1 && t2)
+                    {
+                        if (!deduceType(t1, sc, t2, parameters, dedtypes))
+                            goto Lnomatch;
+                    }
+                    else if (e1 && e2)
+                    {
+                    Le:
+                        e1 = e1->ctfeInterpret();
+
+                        /* If it is one of the template parameters for this template,
+                         * we should not attempt to interpret it. It already has a value.
+                         */
+                        if (e2->op == TOKvar &&
+                            (((VarExp *)e2)->var->storage_class & STCtemplateparameter))
+                        {
+                            /*
+                             * (T:Number!(e2), int e2)
+                             */
+                            j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters);
+                            if (j != IDX_NOTFOUND)
+                                goto L1;
+                            // The template parameter was not from this template
+                            // (it may be from a parent template, for example)
+                        }
+
+                        e2 = ::semantic(e2, sc);      // Bugzilla 13417
+                        e2 = e2->ctfeInterpret();
+
+                        //printf("e1 = %s, type = %s %d\n", e1->toChars(), e1->type->toChars(), e1->type->ty);
+                        //printf("e2 = %s, type = %s %d\n", e2->toChars(), e2->type->toChars(), e2->type->ty);
+                        if (!e1->equals(e2))
+                        {
+                            if (!e2->implicitConvTo(e1->type))
+                                goto Lnomatch;
+
+                            e2 = e2->implicitCastTo(sc, e1->type);
+                            e2 = e2->ctfeInterpret();
+                            if (!e1->equals(e2))
+                                goto Lnomatch;
+                        }
+                    }
+                    else if (e1 && t2 && t2->ty == Tident)
+                    {
+                        j = templateParameterLookup(t2, parameters);
+                    L1:
+                        if (j == IDX_NOTFOUND)
+                        {
+                            t2->resolve(((TypeIdentifier *)t2)->loc, sc, &e2, &t2, &s2);
+                            if (e2)
+                                goto Le;
+                            goto Lnomatch;
+                        }
+                        if (!(*parameters)[j]->matchArg(sc, e1, j, parameters, dedtypes, NULL))
+                            goto Lnomatch;
+                    }
+                    else if (s1 && s2)
+                    {
+                    Ls:
+                        if (!s1->equals(s2))
+                            goto Lnomatch;
+                    }
+                    else if (s1 && t2 && t2->ty == Tident)
+                    {
+                        j = templateParameterLookup(t2, parameters);
+                        if (j == IDX_NOTFOUND)
+                        {
+                            t2->resolve(((TypeIdentifier *)t2)->loc, sc, &e2, &t2, &s2);
+                            if (s2)
+                                goto Ls;
+                            goto Lnomatch;
+                        }
+                        if (!(*parameters)[j]->matchArg(sc, s1, j, parameters, dedtypes, NULL))
+                            goto Lnomatch;
+                    }
+                    else
+                        goto Lnomatch;
+                }
+            }
+            visit((Type *)t);
+            return;
+
+        Lnomatch:
+            //printf("no match\n");
+            result = MATCHnomatch;
+        }
+
+        void visit(TypeStruct *t)
+        {
+#if 0
+            printf("TypeStruct::deduceType()\n");
+            printf("\tthis->parent   = %s, ", t->sym->parent->toChars()); t->print();
+            printf("\ttparam = %d, ", tparam->ty); tparam->print();
+#endif
+
+            /* 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 = t->sym->parent->isTemplateInstance();
+
+            if (tparam && tparam->ty == Tinstance)
+            {
+                if (ti && ti->toAlias() == t->sym)
+                {
+                    TypeInstance *tx = new TypeInstance(Loc(), ti);
+                    result = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
+                    return;
+                }
+
+                /* Match things like:
+                 *  S!(T).foo
+                 */
+                TypeInstance *tpi = (TypeInstance *)tparam;
+                if (tpi->idents.dim)
+                {
+                    RootObject *id = tpi->idents[tpi->idents.dim - 1];
+                    if (id->dyncast() == DYNCAST_IDENTIFIER && t->sym->ident->equals((Identifier *)id))
+                    {
+                        Type *tparent = t->sym->parent->getType();
+                        if (tparent)
+                        {
+                            /* Slice off the .foo in S!(T).foo
+                             */
+                            tpi->idents.dim--;
+                            result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
+                            tpi->idents.dim++;
+                            return;
+                        }
+                    }
+                }
+            }
+
+            // Extra check
+            if (tparam && tparam->ty == Tstruct)
+            {
+                TypeStruct *tp = (TypeStruct *)tparam;
+
+                //printf("\t%d\n", (MATCH) t->implicitConvTo(tp));
+                if (wm && t->deduceWild(tparam, false))
+                {
+                    result = MATCHconst;
+                    return;
+                }
+                result = t->implicitConvTo(tp);
+                return;
+            }
+            visit((Type *)t);
+        }
+
+        void visit(TypeEnum *t)
+        {
+            // Extra check
+            if (tparam && tparam->ty == Tenum)
+            {
+                TypeEnum *tp = (TypeEnum *)tparam;
+                if (t->sym == tp->sym)
+                    visit((Type *)t);
+                else
+                    result = MATCHnomatch;
+                return;
+            }
+            Type *tb = t->toBasetype();
+            if (tb->ty == tparam->ty ||
+                tb->ty == Tsarray && tparam->ty == Taarray)
+            {
+                result = deduceType(tb, sc, tparam, parameters, dedtypes, wm);
+                return;
+            }
+            visit((Type *)t);
+        }
+
+        /* Helper for TypeClass::deduceType().
+         * Classes can match with implicit conversion to a base class or interface.
+         * This is complicated, because there may be more than one base class which
+         * matches. In such cases, one or more parameters remain ambiguous.
+         * For example,
+         *
+         *   interface I(X, Y) {}
+         *   class C : I(uint, double), I(char, double) {}
+         *   C x;
+         *   foo(T, U)( I!(T, U) x)
+         *
+         *   deduces that U is double, but T remains ambiguous (could be char or uint).
+         *
+         * Given a baseclass b, and initial deduced types 'dedtypes', this function
+         * tries to match tparam with b, and also tries all base interfaces of b.
+         * If a match occurs, numBaseClassMatches is incremented, and the new deduced
+         * types are ANDed with the current 'best' estimate for dedtypes.
+         */
+        static void deduceBaseClassParameters(BaseClass *b,
+            Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes,
+            Objects *best, int &numBaseClassMatches)
+        {
+            TemplateInstance *parti = b->sym ? b->sym->parent->isTemplateInstance() : NULL;
+            if (parti)
+            {
+                // Make a temporary copy of dedtypes so we don't destroy it
+                Objects *tmpdedtypes = new Objects();
+                tmpdedtypes->setDim(dedtypes->dim);
+                memcpy(tmpdedtypes->tdata(), dedtypes->tdata(), dedtypes->dim * sizeof(void *));
+
+                TypeInstance *t = new TypeInstance(Loc(), parti);
+                MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes);
+                if (m > MATCHnomatch)
+                {
+                    // If this is the first ever match, it becomes our best estimate
+                    if (numBaseClassMatches==0)
+                        memcpy(best->tdata(), tmpdedtypes->tdata(), tmpdedtypes->dim * sizeof(void *));
+                    else for (size_t k = 0; k < tmpdedtypes->dim; ++k)
+                    {
+                        // If we've found more than one possible type for a parameter,
+                        // mark it as unknown.
+                        if ((*tmpdedtypes)[k] != (*best)[k])
+                            (*best)[k] = (*dedtypes)[k];
+                    }
+                    ++numBaseClassMatches;
+                }
+            }
+            // Now recursively test the inherited interfaces
+            for (size_t j = 0; j < b->baseInterfaces.length; ++j)
+            {
+                BaseClass *bi = &b->baseInterfaces.ptr[j];
+                deduceBaseClassParameters(bi,
+                    sc, tparam, parameters, dedtypes,
+                    best, numBaseClassMatches);
+            }
+
+        }
+
+        void visit(TypeClass *t)
+        {
+            //printf("TypeClass::deduceType(this = %s)\n", t->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 = t->sym->parent->isTemplateInstance();
+
+            if (tparam && tparam->ty == Tinstance)
+            {
+                if (ti && ti->toAlias() == t->sym)
+                {
+                    TypeInstance *tx = new TypeInstance(Loc(), ti);
+                    MATCH m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
+                    // Even if the match fails, there is still a chance it could match
+                    // a base class.
+                    if (m != MATCHnomatch)
+                    {
+                        result = m;
+                        return;
+                    }
+                }
+
+                /* Match things like:
+                 *  S!(T).foo
+                 */
+                TypeInstance *tpi = (TypeInstance *)tparam;
+                if (tpi->idents.dim)
+                {
+                    RootObject *id = tpi->idents[tpi->idents.dim - 1];
+                    if (id->dyncast() == DYNCAST_IDENTIFIER && t->sym->ident->equals((Identifier *)id))
+                    {
+                        Type *tparent = t->sym->parent->getType();
+                        if (tparent)
+                        {
+                            /* Slice off the .foo in S!(T).foo
+                             */
+                            tpi->idents.dim--;
+                            result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
+                            tpi->idents.dim++;
+                            return;
+                        }
+                    }
+                }
+
+                // If it matches exactly or via implicit conversion, we're done
+                visit((Type *)t);
+                if (result != MATCHnomatch)
+                    return;
+
+                /* There is still a chance to match via implicit conversion to
+                 * a base class or interface. Because there could be more than one such
+                 * match, we need to check them all.
+                 */
+
+                int numBaseClassMatches = 0; // Have we found an interface match?
+
+                // Our best guess at dedtypes
+                Objects *best = new Objects();
+                best->setDim(dedtypes->dim);
+
+                ClassDeclaration *s = t->sym;
+                while (s && s->baseclasses->dim > 0)
+                {
+                    // Test the base class
+                    deduceBaseClassParameters((*s->baseclasses)[0],
+                        sc, tparam, parameters, dedtypes,
+                        best, numBaseClassMatches);
+
+                    // Test the interfaces inherited by the base class
+                    for (size_t i = 0; i < s->interfaces.length; ++i)
+                    {
+                        BaseClass *b = s->interfaces.ptr[i];
+                        deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes,
+                            best, numBaseClassMatches);
+                    }
+                    s = (*s->baseclasses)[0]->sym;
+                }
+
+                if (numBaseClassMatches == 0)
+                {
+                    result = MATCHnomatch;
+                    return;
+                }
+
+                // If we got at least one match, copy the known types into dedtypes
+                memcpy(dedtypes->tdata(), best->tdata(), best->dim * sizeof(void *));
+                result = MATCHconvert;
+                return;
+            }
+
+            // Extra check
+            if (tparam && tparam->ty == Tclass)
+            {
+                TypeClass *tp = (TypeClass *)tparam;
+
+                //printf("\t%d\n", (MATCH) t->implicitConvTo(tp));
+                if (wm && t->deduceWild(tparam, false))
+                {
+                    result = MATCHconst;
+                    return;
+                }
+                result = t->implicitConvTo(tp);
+                return;
+            }
+            visit((Type *)t);
+        }
+
+        void visit(Expression *e)
+        {
+            //printf("Expression::deduceType(e = %s)\n", e->toChars());
+            size_t i = templateParameterLookup(tparam, parameters);
+            if (i == IDX_NOTFOUND || ((TypeIdentifier *)tparam)->idents.dim > 0)
+            {
+                if (e == emptyArrayElement && tparam->ty == Tarray)
+                {
+                    Type *tn = ((TypeNext *)tparam)->next;
+                    result = deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
+                    return;
+                }
+                e->type->accept(this);
+                return;
+            }
+
+            TemplateTypeParameter *tp = (*parameters)[i]->isTemplateTypeParameter();
+            if (!tp)
+                return; // nomatch
+
+            if (e == emptyArrayElement)
+            {
+                if ((*dedtypes)[i])
+                {
+                    result = MATCHexact;
+                    return;
+                }
+                if (tp->defaultType)
+                {
+                    tp->defaultType->accept(this);
+                    return;
+                }
+            }
+
+            Type *at = (Type *)(*dedtypes)[i];
+            Type *tt;
+            if (unsigned char wx = deduceWildHelper(e->type, &tt, tparam))
+            {
+                *wm |= wx;
+                result = MATCHconst;
+            }
+            else if (MATCH m = deduceTypeHelper(e->type, &tt, tparam))
+            {
+                result = m;
+            }
+            else
+                return; // nomatch
+
+            // expression vs (none)
+            if (!at)
+            {
+                (*dedtypes)[i] = new TypeDeduced(tt, e, tparam);
+                return;
+            }
+
+            TypeDeduced *xt = NULL;
+            if (at->ty == Tnone)
+            {
+                xt = (TypeDeduced *)at;
+                at = xt->tded;
+            }
+
+            // From previous matched expressions to current deduced type
+            MATCH match1 = xt ? xt->matchAll(tt) : MATCHnomatch;
+
+            // From current expresssion to previous deduced type
+            Type *pt = at->addMod(tparam->mod);
+            if (*wm)
+                pt = pt->substWildTo(*wm);
+            MATCH match2 = e->implicitConvTo(pt);
+
+            if (match1 > MATCHnomatch && match2 > MATCHnomatch)
+            {
+                if (at->implicitConvTo(tt) <= MATCHnomatch)
+                    match1 = MATCHnomatch;  // Prefer at
+                else if (tt->implicitConvTo(at) <= MATCHnomatch)
+                    match2 = MATCHnomatch;  // Prefer tt
+                else if (tt->isTypeBasic() && tt->ty == at->ty && tt->mod != at->mod)
+                {
+                    if (!tt->isMutable() && !at->isMutable())
+                        tt = tt->mutableOf()->addMod(MODmerge(tt->mod, at->mod));
+                    else if (tt->isMutable())
+                    {
+                        if (at->mod == 0)   // Prefer unshared
+                            match1 = MATCHnomatch;
+                        else
+                            match2 = MATCHnomatch;
+                    }
+                    else if (at->isMutable())
+                    {
+                        if (tt->mod == 0)   // Prefer unshared
+                            match2 = MATCHnomatch;
+                        else
+                            match1 = MATCHnomatch;
+                    }
+                    //printf("tt = %s, at = %s\n", tt->toChars(), at->toChars());
+                }
+                else
+                {
+                    match1 = MATCHnomatch;
+                    match2 = MATCHnomatch;
+                }
+            }
+            if (match1 > MATCHnomatch)
+            {
+                // Prefer current match: tt
+                if (xt)
+                    xt->update(tt, e, tparam);
+                else
+                    (*dedtypes)[i] = tt;
+                result = match1;
+                return;
+            }
+            if (match2 > MATCHnomatch)
+            {
+                // Prefer previous match: (*dedtypes)[i]
+                if (xt)
+                    xt->update(e, tparam);
+                result = match2;
+                return;
+            }
+
+            /* Deduce common type
+             */
+            if (Type *t = rawTypeMerge(at, tt))
+            {
+                if (xt)
+                    xt->update(t, e, tparam);
+                else
+                    (*dedtypes)[i] = t;
+
+                pt = tt->addMod(tparam->mod);
+                if (*wm)
+                    pt = pt->substWildTo(*wm);
+                result = e->implicitConvTo(pt);
+                return;
+            }
+
+            result = MATCHnomatch;
+        }
+
+        MATCH deduceEmptyArrayElement()
+        {
+            if (!emptyArrayElement)
+            {
+                emptyArrayElement = new IdentifierExp(Loc(), Id::p);    // dummy
+                emptyArrayElement->type = Type::tvoid;
+            }
+            assert(tparam->ty == Tarray);
+
+            Type *tn = ((TypeNext *)tparam)->next;
+            return deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
+        }
+
+        void visit(NullExp *e)
+        {
+            if (tparam->ty == Tarray && e->type->ty == Tnull)
+            {
+                // tparam:T[] <- e:null (void[])
+                result = deduceEmptyArrayElement();
+                return;
+            }
+            visit((Expression *)e);
+        }
+
+        void visit(StringExp *e)
+        {
+            Type *taai;
+            if (e->type->ty == Tarray &&
+                (tparam->ty == Tsarray ||
+                 tparam->ty == Taarray && (taai = ((TypeAArray *)tparam)->index)->ty == Tident &&
+                                          ((TypeIdentifier *)taai)->idents.dim == 0))
+            {
+                // Consider compile-time known boundaries
+                e->type->nextOf()->sarrayOf(e->len)->accept(this);
+                return;
+            }
+            visit((Expression *)e);
+        }
+
+        void visit(ArrayLiteralExp *e)
+        {
+            if ((!e->elements || !e->elements->dim) &&
+                e->type->toBasetype()->nextOf()->ty == Tvoid &&
+                tparam->ty == Tarray)
+            {
+                // tparam:T[] <- e:[] (void[])
+                result = deduceEmptyArrayElement();
+                return;
+            }
+
+            if (tparam->ty == Tarray && e->elements && e->elements->dim)
+            {
+                Type *tn = ((TypeDArray *)tparam)->next;
+                result = MATCHexact;
+                if (e->basis)
+                {
+                    MATCH m = deduceType(e->basis, sc, tn, parameters, dedtypes, wm);
+                    if (m < result)
+                        result = m;
+                }
+                for (size_t i = 0; i < e->elements->dim; i++)
+                {
+                    if (result <= MATCHnomatch)
+                        break;
+                    Expression *el = (*e->elements)[i];
+                    if (!el)
+                        continue;
+                    MATCH m = deduceType(el, sc, tn, parameters, dedtypes, wm);
+                    if (m < result)
+                        result = m;
+                }
+                return;
+            }
+
+            Type *taai;
+            if (e->type->ty == Tarray &&
+                (tparam->ty == Tsarray ||
+                 tparam->ty == Taarray && (taai = ((TypeAArray *)tparam)->index)->ty == Tident &&
+                                          ((TypeIdentifier *)taai)->idents.dim == 0))
+            {
+                // Consider compile-time known boundaries
+                e->type->nextOf()->sarrayOf(e->elements->dim)->accept(this);
+                return;
+            }
+            visit((Expression *)e);
+        }
+
+        void visit(AssocArrayLiteralExp *e)
+        {
+            if (tparam->ty == Taarray && e->keys && e->keys->dim)
+            {
+                TypeAArray *taa = (TypeAArray *)tparam;
+                result = MATCHexact;
+                for (size_t i = 0; i < e->keys->dim; i++)
+                {
+                    MATCH m1 = deduceType((*e->keys)[i], sc, taa->index, parameters, dedtypes, wm);
+                    if (m1 < result)
+                        result = m1;
+                    if (result <= MATCHnomatch)
+                        break;
+                    MATCH m2 = deduceType((*e->values)[i], sc, taa->next, parameters, dedtypes, wm);
+                    if (m2 < result)
+                        result = m2;
+                    if (result <= MATCHnomatch)
+                        break;
+                }
+                return;
+            }
+            visit((Expression *)e);
+        }
+
+        void visit(FuncExp *e)
+        {
+            //printf("e->type = %s, tparam = %s\n", e->type->toChars(), tparam->toChars());
+            if (e->td)
+            {
+                Type *to = tparam;
+                if (!to->nextOf() || to->nextOf()->ty != Tfunction)
+                    return;
+                TypeFunction *tof = (TypeFunction *)to->nextOf();
+
+                // Parameter types inference from 'tof'
+                assert(e->td->_scope);
+                TypeFunction *tf = (TypeFunction *)e->fd->type;
+                //printf("\ttof = %s\n", tof->toChars());
+                //printf("\ttf  = %s\n", tf->toChars());
+                size_t dim = Parameter::dim(tf->parameters);
+
+                if (Parameter::dim(tof->parameters) != dim ||
+                    tof->varargs != tf->varargs)
+                    return;
+
+                Objects *tiargs = new Objects();
+                tiargs->reserve(e->td->parameters->dim);
+
+                for (size_t i = 0; i < e->td->parameters->dim; i++)
+                {
+                    TemplateParameter *tp = (*e->td->parameters)[i];
+                    size_t u = 0;
+                    for (; u < dim; u++)
+                    {
+                        Parameter *p = Parameter::getNth(tf->parameters, u);
+                        if (p->type->ty == Tident &&
+                            ((TypeIdentifier *)p->type)->ident == tp->ident)
+                        {
+                            break;
+                        }
+                    }
+                    assert(u < dim);
+                    Parameter *pto = Parameter::getNth(tof->parameters, u);
+                    if (!pto)
+                        break;
+                    Type *t = pto->type->syntaxCopy();  // Bugzilla 11774
+                    if (reliesOnTident(t, parameters, inferStart))
+                        return;
+                    t = t->semantic(e->loc, sc);
+                    if (t->ty == Terror)
+                        return;
+                    tiargs->push(t);
+                }
+
+                // Set target of return type inference
+                if (!tf->next && tof->next)
+                    e->fd->treq = tparam;
+
+                TemplateInstance *ti = new TemplateInstance(e->loc, e->td, tiargs);
+                Expression *ex = new ScopeExp(e->loc, ti);
+                ex = ::semantic(ex, e->td->_scope);
+
+                // Reset inference target for the later re-semantic
+                e->fd->treq = NULL;
+
+                if (ex->op == TOKerror)
+                    return;
+                if (ex->op != TOKfunction)
+                    return;
+                visit(ex->type);
+                return;
+            }
+
+            Type *t = e->type;
+
+            if (t->ty == Tdelegate && tparam->ty == Tpointer)
+                return;
+
+            // Allow conversion from implicit function pointer to delegate
+            if (e->tok == TOKreserved &&
+                t->ty == Tpointer && tparam->ty == Tdelegate)
+            {
+                TypeFunction *tf = (TypeFunction *)t->nextOf();
+                t = (new TypeDelegate(tf))->merge();
+            }
+            //printf("tparam = %s <= e->type = %s, t = %s\n", tparam->toChars(), e->type->toChars(), t->toChars());
+            visit(t);
+        }
+
+        void visit(SliceExp *e)
+        {
+            Type *taai;
+            if (e->type->ty == Tarray &&
+                (tparam->ty == Tsarray ||
+                 tparam->ty == Taarray && (taai = ((TypeAArray *)tparam)->index)->ty == Tident &&
+                                          ((TypeIdentifier *)taai)->idents.dim == 0))
+            {
+                // Consider compile-time known boundaries
+                if (Type *tsa = toStaticArrayType(e))
+                {
+                    tsa->accept(this);
+                    return;
+                }
+            }
+            visit((Expression *)e);
+        }
+
+        void visit(CommaExp *e)
+        {
+            ((CommaExp *)e)->e2->accept(this);
+        }
+    };
+
+    DeduceType v(sc, tparam, parameters, dedtypes, wm, inferStart);
+    if (Type *t = isType(o))
+        t->accept(&v);
+    else
+    {
+        assert(isExpression(o) && wm);
+        ((Expression *)o)->accept(&v);
+    }
+    return v.result;
+}
+
+/*******************************
+ * Input:
+ *      t           Tested type, if NULL, returns NULL.
+ *      tparams     Optional template parameters.
+ *                  == NULL:
+ *                      If one of the subtypes of this type is a TypeIdentifier,
+ *                      i.e. it's an unresolved type, return that type.
+ *                  != NULL:
+ *                      Only when the TypeIdentifier is one of template parameters,
+ *                      return that type.
+ */
+
+Type *reliesOnTident(Type *t, TemplateParameters *tparams, size_t iStart)
+{
+    class ReliesOnTident : public Visitor
+    {
+    public:
+        TemplateParameters *tparams;
+        size_t iStart;
+        Type *result;
+
+        ReliesOnTident(TemplateParameters *tparams, size_t iStart)
+            : tparams(tparams), iStart(iStart)
+        {
+            result = NULL;
+        }
+
+        void visit(Type *t)
+        {
+        }
+
+        void visit(TypeNext *t)
+        {
+            t->next->accept(this);
+        }
+
+        void visit(TypeVector *t)
+        {
+            t->basetype->accept(this);
+        }
+
+        void visit(TypeAArray *t)
+        {
+            visit((TypeNext *)t);
+            if (!result)
+                t->index->accept(this);
+        }
+
+        void visit(TypeFunction *t)
+        {
+            size_t dim = Parameter::dim(t->parameters);
+            for (size_t i = 0; i < dim; i++)
+            {
+                Parameter *fparam = Parameter::getNth(t->parameters, i);
+                fparam->type->accept(this);
+                if (result)
+                    return;
+            }
+            if (t->next)
+                t->next->accept(this);
+        }
+
+        void visit(TypeIdentifier *t)
+        {
+            if (!tparams)
+            {
+                result = t;
+                return;
+            }
+
+            for (size_t i = iStart; i < tparams->dim; i++)
+            {
+                TemplateParameter *tp = (*tparams)[i];
+                if (tp->ident->equals(t->ident))
+                {
+                    result = t;
+                    return;
+                }
+            }
+        }
+
+        void visit(TypeInstance *t)
+        {
+            if (!tparams)
+                return;
+
+            for (size_t i = iStart; i < tparams->dim; i++)
+            {
+                TemplateParameter *tp = (*tparams)[i];
+                if (t->tempinst->name == tp->ident)
+                {
+                    result = t;
+                    return;
+                }
+            }
+            if (!t->tempinst->tiargs)
+                return;
+            for (size_t i = 0; i < t->tempinst->tiargs->dim; i++)
+            {
+                Type *ta = isType((*t->tempinst->tiargs)[i]);
+                if (ta)
+                {
+                    ta->accept(this);
+                    if (result)
+                        return;
+                }
+            }
+        }
+
+        void visit(TypeTuple *t)
+        {
+            if (t->arguments)
+            {
+                for (size_t i = 0; i < t->arguments->dim; i++)
+                {
+                    Parameter *arg = (*t->arguments)[i];
+                    arg->type->accept(this);
+                    if (result)
+                        return;
+                }
+            }
+        }
+    };
+
+    if (!t)
+        return NULL;
+
+    ReliesOnTident v(tparams, iStart);
+    t->accept(&v);
+    return v.result;
+}
+
+/* ======================== TemplateParameter =============================== */
+
+TemplateParameter::TemplateParameter(Loc loc, Identifier *ident)
+{
+    this->loc = loc;
+    this->ident = ident;
+    this->dependent = false;
+}
+
+TemplateTypeParameter  *TemplateParameter::isTemplateTypeParameter()
+{
+    return NULL;
+}
+
+TemplateValueParameter *TemplateParameter::isTemplateValueParameter()
+{
+    return NULL;
+}
+
+TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter()
+{
+    return NULL;
+}
+
+TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter()
+{
+    return NULL;
+}
+
+TemplateThisParameter  *TemplateParameter::isTemplateThisParameter()
+{
+    return NULL;
+}
+
+/*******************************************
+ * Match to a particular TemplateParameter.
+ * Input:
+ *      instLoc         location that the template is instantiated.
+ *      tiargs[]        actual arguments to template instance
+ *      i               i'th argument
+ *      parameters[]    template parameters
+ *      dedtypes[]      deduced arguments to template instance
+ *      *psparam        set to symbol declared and initialized to dedtypes[i]
+ */
+MATCH TemplateParameter::matchArg(Loc instLoc, Scope *sc, Objects *tiargs,
+        size_t i, TemplateParameters *parameters, Objects *dedtypes,
+        Declaration **psparam)
+{
+    RootObject *oarg;
+
+    if (i < tiargs->dim)
+        oarg = (*tiargs)[i];
+    else
+    {
+        // Get default argument instead
+        oarg = defaultArg(instLoc, sc);
+        if (!oarg)
+        {
+            assert(i < dedtypes->dim);
+            // It might have already been deduced
+            oarg = (*dedtypes)[i];
+            if (!oarg)
+                goto Lnomatch;
+        }
+    }
+    return matchArg(sc, oarg, i, parameters, dedtypes, psparam);
+
+Lnomatch:
+    if (psparam)
+        *psparam = NULL;
+    return MATCHnomatch;
+}
+
+/* ======================== TemplateTypeParameter =========================== */
+
+// type-parameter
+
+Type *TemplateTypeParameter::tdummy = NULL;
+
+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()
+{
+    return new TemplateTypeParameter(loc, ident,
+        specType    ? specType->syntaxCopy()    : NULL,
+        defaultType ? defaultType->syntaxCopy() : NULL);
+}
+
+bool TemplateTypeParameter::declareParameter(Scope *sc)
+{
+    //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars());
+    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+    Declaration *ad = new AliasDeclaration(loc, ident, ti);
+    return sc->insert(ad) != NULL;
+}
+
+bool TemplateTypeParameter::semantic(Scope *sc, TemplateParameters *parameters)
+{
+    //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars());
+    if (specType && !reliesOnTident(specType, parameters))
+    {
+        specType = specType->semantic(loc, sc);
+    }
+#if 0 // Don't do semantic() until instantiation
+    if (defaultType)
+    {
+        defaultType = defaultType->semantic(loc, sc);
+    }
+#endif
+    return !(specType && isError(specType));
+}
+
+MATCH TemplateTypeParameter::matchArg(Scope *sc, RootObject *oarg,
+        size_t i, TemplateParameters *parameters, Objects *dedtypes,
+        Declaration **psparam)
+{
+    //printf("TemplateTypeParameter::matchArg('%s')\n", ident->toChars());
+    MATCH m = MATCHexact;
+    Type *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());
+
+    if (specType)
+    {
+        if (!ta || ta == tdummy)
+            goto Lnomatch;
+
+        //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars());
+        MATCH m2 = deduceType(ta, sc, specType, parameters, dedtypes);
+        if (m2 <= MATCHnomatch)
+        {
+            //printf("\tfailed deduceType\n");
+            goto Lnomatch;
+        }
+
+        if (m2 < m)
+            m = m2;
+        if ((*dedtypes)[i])
+        {
+            Type *t = (Type *)(*dedtypes)[i];
+
+            if (dependent && !t->equals(ta))    // Bugzilla 14357
+                goto Lnomatch;
+
+            /* This is a self-dependent parameter. For example:
+             *  template X(T : T*) {}
+             *  template X(T : S!T, alias S) {}
+             */
+            //printf("t = %s ta = %s\n", t->toChars(), ta->toChars());
+            ta = t;
+        }
+    }
+    else
+    {
+        if ((*dedtypes)[i])
+        {
+            // Must match already deduced type
+            Type *t = (Type *)(*dedtypes)[i];
+
+            if (!t->equals(ta))
+            {
+                //printf("t = %s ta = %s\n", t->toChars(), ta->toChars());
+                goto Lnomatch;
+            }
+        }
+        else
+        {
+            // So that matches with specializations are better
+            m = MATCHconvert;
+        }
+    }
+    (*dedtypes)[i] = ta;
+
+    if (psparam)
+        *psparam = new AliasDeclaration(loc, ident, ta);
+    //printf("\tm = %d\n", m);
+    return dependent ? MATCHexact : m;
+
+Lnomatch:
+    if (psparam)
+        *psparam = NULL;
+    //printf("\tm = %d\n", MATCHnomatch);
+    return MATCHnomatch;
+}
+
+
+void TemplateTypeParameter::print(RootObject *oarg, RootObject *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("\tParameter:       %s\n", t ? t->toChars() : "NULL");
+    printf("\tDeduced Type:   %s\n", ta->toChars());
+}
+
+void *TemplateTypeParameter::dummyArg()
+{
+    Type *t = specType;
+    if (!t)
+    {
+        // Use this for alias-parameter's too (?)
+        if (!tdummy)
+            tdummy = new TypeIdentifier(loc, ident);
+        t = tdummy;
+    }
+    return (void *)t;
+}
+
+
+RootObject *TemplateTypeParameter::specialization()
+{
+    return specType;
+}
+
+RootObject *TemplateTypeParameter::defaultArg(Loc instLoc, Scope *sc)
+{
+    Type *t = defaultType;
+    if (t)
+    {
+        t = t->syntaxCopy();
+        t = t->semantic(loc, sc);   // use the parameter loc
+    }
+    return t;
+}
+
+bool TemplateTypeParameter::hasDefaultArg()
+{
+    return defaultType != NULL;
+}
+
+/* ======================== TemplateThisParameter =========================== */
+
+// 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()
+{
+    return new TemplateThisParameter(loc, ident,
+        specType    ? specType->syntaxCopy()    : NULL,
+        defaultType ? defaultType->syntaxCopy() : NULL);
+}
+
+/* ======================== TemplateAliasParameter ========================== */
+
+// alias-parameter
+
+Dsymbol *TemplateAliasParameter::sdummy = NULL;
+
+TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident,
+        Type *specType, RootObject *specAlias, RootObject *defaultAlias)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+    this->specType = specType;
+    this->specAlias = specAlias;
+    this->defaultAlias = defaultAlias;
+}
+
+TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateAliasParameter::syntaxCopy()
+{
+    return new TemplateAliasParameter(loc, ident,
+        specType ? specType->syntaxCopy() : NULL,
+        objectSyntaxCopy(specAlias),
+        objectSyntaxCopy(defaultAlias));
+}
+
+bool TemplateAliasParameter::declareParameter(Scope *sc)
+{
+    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+    Declaration *ad = new AliasDeclaration(loc, ident, ti);
+    return sc->insert(ad) != NULL;
+}
+
+static RootObject *aliasParameterSemantic(Loc loc, Scope *sc, RootObject *o, TemplateParameters *parameters)
+{
+    if (o)
+    {
+        Expression *ea = isExpression(o);
+        Type *ta = isType(o);
+        if (ta && (!parameters || !reliesOnTident(ta, parameters)))
+        {
+            Dsymbol *s = ta->toDsymbol(sc);
+            if (s)
+                o = s;
+            else
+                o = ta->semantic(loc, sc);
+        }
+        else if (ea)
+        {
+            sc = sc->startCTFE();
+            ea = ::semantic(ea, sc);
+            sc = sc->endCTFE();
+            o = ea->ctfeInterpret();
+        }
+    }
+    return o;
+}
+
+bool TemplateAliasParameter::semantic(Scope *sc, TemplateParameters *parameters)
+{
+    if (specType && !reliesOnTident(specType, parameters))
+    {
+        specType = specType->semantic(loc, sc);
+    }
+    specAlias = aliasParameterSemantic(loc, sc, specAlias, parameters);
+#if 0 // Don't do semantic() until instantiation
+    if (defaultAlias)
+        defaultAlias = defaultAlias->semantic(loc, sc);
+#endif
+    return !(specType  && isError(specType)) &&
+           !(specAlias && isError(specAlias));
+}
+
+MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg,
+        size_t i, TemplateParameters *parameters, Objects *dedtypes,
+        Declaration **psparam)
+{
+    //printf("TemplateAliasParameter::matchArg('%s')\n", ident->toChars());
+    MATCH m = MATCHexact;
+    Type *ta = isType(oarg);
+    RootObject *sa = ta && !ta->deco ? NULL : getDsymbol(oarg);
+    Expression *ea = isExpression(oarg);
+    if (ea && (ea->op == TOKthis || ea->op == TOKsuper))
+        sa = ((ThisExp *)ea)->var;
+    else if (ea && ea->op == TOKscope)
+        sa = ((ScopeExp *)ea)->sds;
+    if (sa)
+    {
+        if (((Dsymbol *)sa)->isAggregateDeclaration())
+            m = MATCHconvert;
+
+        /* 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;
+        if (ea)
+        {
+            if (specType)
+            {
+                if (!ea->type->equals(specType))
+                    goto Lnomatch;
+            }
+        }
+        else if (ta && ta->ty == Tinstance && !specAlias)
+        {
+            /* Bugzilla xxxxx: Specialized parameter should be prefeerd
+             * match to the template type parameter.
+             *  template X(alias a) {}                      // a == this
+             *  template X(alias a : B!A, alias B, A...) {} // B!A => ta
+             */
+        }
+        else if (sa && sa == TemplateTypeParameter::tdummy)
+        {
+            /* Bugzilla 2025: Aggregate Types should preferentially
+             * match to the template type parameter.
+             *  template X(alias a) {}  // a == this
+             *  template X(T) {}        // T => sa
+             */
+        }
+        else
+            goto Lnomatch;
+    }
+
+    if (specAlias)
+    {
+        if (sa == sdummy)
+            goto Lnomatch;
+        Dsymbol *sx = isDsymbol(sa);
+        if (sa != specAlias && sx)
+        {
+            Type *talias = isType(specAlias);
+            if (!talias)
+                goto Lnomatch;
+
+            TemplateInstance *ti = sx->isTemplateInstance();
+            if (!ti && sx->parent)
+            {
+                ti = sx->parent->isTemplateInstance();
+                if (ti && ti->name != sx->ident)
+                    goto Lnomatch;
+            }
+            if (!ti)
+                goto Lnomatch;
+
+            Type *t = new TypeInstance(Loc(), ti);
+            MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes);
+            if (m2 <= MATCHnomatch)
+                goto Lnomatch;
+        }
+    }
+    else if ((*dedtypes)[i])
+    {
+        // Must match already deduced symbol
+        RootObject *si = (*dedtypes)[i];
+        if (!sa || si != sa)
+            goto Lnomatch;
+    }
+    (*dedtypes)[i] = sa;
+
+    if (psparam)
+    {
+        if (Dsymbol *s = isDsymbol(sa))
+        {
+            *psparam = new AliasDeclaration(loc, ident, s);
+        }
+        else if (Type *t = isType(sa))
+        {
+            *psparam = new AliasDeclaration(loc, ident, t);
+        }
+        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 dependent ? MATCHexact : m;
+
+Lnomatch:
+    if (psparam)
+        *psparam = NULL;
+    //printf("\tm = %d\n", MATCHnomatch);
+    return MATCHnomatch;
+}
+
+
+void TemplateAliasParameter::print(RootObject *oarg, RootObject *oded)
+{
+    printf(" %s\n", ident->toChars());
+
+    Dsymbol *sa = isDsymbol(oded);
+    assert(sa);
+
+    printf("\tParameter alias: %s\n", sa->toChars());
+}
+
+void *TemplateAliasParameter::dummyArg()
+{
+    RootObject *s = specAlias;
+    if (!s)
+    {
+        if (!sdummy)
+            sdummy = new Dsymbol();
+        s = sdummy;
+    }
+    return (void*)s;
+}
+
+
+RootObject *TemplateAliasParameter::specialization()
+{
+    return specAlias;
+}
+
+RootObject *TemplateAliasParameter::defaultArg(Loc instLoc, Scope *sc)
+{
+    RootObject *da = defaultAlias;
+    Type *ta = isType(defaultAlias);
+    if (ta)
+    {
+       if (ta->ty == Tinstance)
+       {
+           // If the default arg is a template, instantiate for each type
+           da = ta->syntaxCopy();
+       }
+    }
+
+    RootObject *o = aliasParameterSemantic(loc, sc, da, NULL);  // use the parameter loc
+    return o;
+}
+
+bool TemplateAliasParameter::hasDefaultArg()
+{
+    return defaultAlias != NULL;
+}
+
+/* ======================== TemplateValueParameter ========================== */
+
+// value-parameter
+
+AA *TemplateValueParameter::edummies = 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()
+{
+    return new TemplateValueParameter(loc, ident,
+        valType->syntaxCopy(),
+        specValue    ? specValue->syntaxCopy()    : NULL,
+        defaultValue ? defaultValue->syntaxCopy() : NULL);
+}
+
+bool TemplateValueParameter::declareParameter(Scope *sc)
+{
+    VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL);
+    v->storage_class = STCtemplateparameter;
+    return sc->insert(v) != NULL;
+}
+
+bool TemplateValueParameter::semantic(Scope *sc, TemplateParameters *parameters)
+{
+    valType = valType->semantic(loc, sc);
+
+#if 0   // defer semantic analysis to arg match
+    if (specValue)
+    {
+        Expression *e = specValue;
+        sc = sc->startCTFE();
+        e = e->semantic(sc);
+        sc = sc->endCTFE();
+        e = e->implicitCastTo(sc, valType);
+        e = e->ctfeInterpret();
+        if (e->op == TOKint64 || e->op == TOKfloat64 ||
+            e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring)
+            specValue = e;
+    }
+
+    if (defaultValue)
+    {
+        Expression *e = defaultValue;
+        sc = sc->startCTFE();
+        e = e->semantic(sc);
+        sc = sc->endCTFE();
+        e = e->implicitCastTo(sc, valType);
+        e = e->ctfeInterpret();
+        if (e->op == TOKint64)
+            defaultValue = e;
+    }
+#endif
+    return !isError(valType);
+}
+
+MATCH TemplateValueParameter::matchArg(Scope *sc, RootObject *oarg,
+        size_t i, TemplateParameters *parameters, Objects *dedtypes,
+        Declaration **psparam)
+{
+    //printf("TemplateValueParameter::matchArg('%s')\n", ident->toChars());
+
+    MATCH m = MATCHexact;
+
+    Expression *ei = isExpression(oarg);
+    Type *vt;
+
+    if (!ei && oarg)
+    {
+        Dsymbol *si = isDsymbol(oarg);
+        FuncDeclaration *f = si ? si->isFuncDeclaration() : NULL;
+        if (!f || !f->fbody || f->needThis())
+            goto Lnomatch;
+
+        ei = new VarExp(loc, f);
+        ei = ::semantic(ei, sc);
+
+        /* If a function is really property-like, and then
+         * it's CTFEable, ei will be a literal expression.
+         */
+        unsigned int olderrors = global.startGagging();
+        ei = resolveProperties(sc, ei);
+        ei = ei->ctfeInterpret();
+        if (global.endGagging(olderrors) || ei->op == TOKerror)
+            goto Lnomatch;
+
+        /* Bugzilla 14520: A property-like function can match to both
+         * TemplateAlias and ValueParameter. But for template overloads,
+         * it should always prefer alias parameter to be consistent
+         * template match result.
+         *
+         *   template X(alias f) { enum X = 1; }
+         *   template X(int val) { enum X = 2; }
+         *   int f1() { return 0; }  // CTFEable
+         *   int f2();               // body-less function is not CTFEable
+         *   enum x1 = X!f1;    // should be 1
+         *   enum x2 = X!f2;    // should be 1
+         *
+         * e.g. The x1 value must be same even if the f1 definition will be moved
+         *      into di while stripping body code.
+         */
+        m = MATCHconvert;
+    }
+
+    if (ei && ei->op == TOKvar)
+    {
+        // Resolve const variables that we had skipped earlier
+        ei = ei->ctfeInterpret();
+    }
+
+    //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty);
+    vt = valType->semantic(loc, sc);
+    //printf("ei: %s, ei->type: %s\n", ei->toChars(), ei->type->toChars());
+    //printf("vt = %s\n", vt->toChars());
+
+    if (ei->type)
+    {
+        MATCH m2 = ei->implicitConvTo(vt);
+        //printf("m: %d\n", m);
+        if (m2 < m)
+            m = m2;
+        if (m <= MATCHnomatch)
+            goto Lnomatch;
+        ei = ei->implicitCastTo(sc, vt);
+        ei = ei->ctfeInterpret();
+    }
+
+    if (specValue)
+    {
+        if (!ei || (Expression *)dmd_aaGetRvalue(edummies, (void *)ei->type) == ei)
+            goto Lnomatch;
+
+        Expression *e = specValue;
+
+        sc = sc->startCTFE();
+        e = ::semantic(e, sc);
+        e = resolveProperties(sc, e);
+        sc = sc->endCTFE();
+        e = e->implicitCastTo(sc, vt);
+        e = e->ctfeInterpret();
+
+        ei = ei->syntaxCopy();
+        sc = sc->startCTFE();
+        ei = ::semantic(ei, sc);
+        sc = sc->endCTFE();
+        ei = ei->implicitCastTo(sc, vt);
+        ei = ei->ctfeInterpret();
+        //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)[i])
+        {
+            // Must match already deduced value
+            Expression *e = (Expression *)(*dedtypes)[i];
+
+            if (!ei || !ei->equals(e))
+                goto Lnomatch;
+        }
+    }
+    (*dedtypes)[i] = ei;
+
+    if (psparam)
+    {
+        Initializer *init = new ExpInitializer(loc, ei);
+        Declaration *sparam = new VarDeclaration(loc, vt, ident, init);
+        sparam->storage_class = STCmanifest;
+        *psparam = sparam;
+    }
+    return dependent ? MATCHexact : m;
+
+Lnomatch:
+    //printf("\tno match\n");
+    if (psparam)
+        *psparam = NULL;
+    return MATCHnomatch;
+}
+
+
+void TemplateValueParameter::print(RootObject *oarg, RootObject *oded)
+{
+    printf(" %s\n", ident->toChars());
+
+    Expression *ea = isExpression(oded);
+
+    if (specValue)
+        printf("\tSpecialization: %s\n", specValue->toChars());
+    printf("\tParameter Value: %s\n", ea ? ea->toChars() : "NULL");
+}
+
+void *TemplateValueParameter::dummyArg()
+{
+    Expression *e = specValue;
+    if (!e)
+    {
+        // Create a dummy value
+        Expression **pe = (Expression **)dmd_aaGet(&edummies, (void *)valType);
+        if (!*pe)
+            *pe = valType->defaultInit();
+        e = *pe;
+    }
+    return (void *)e;
+}
+
+
+RootObject *TemplateValueParameter::specialization()
+{
+    return specValue;
+}
+
+RootObject *TemplateValueParameter::defaultArg(Loc instLoc, Scope *sc)
+{
+    Expression *e = defaultValue;
+    if (e)
+    {
+        e = e->syntaxCopy();
+        e = ::semantic(e, sc);
+        e = resolveProperties(sc, e);
+        e = e->resolveLoc(instLoc, sc);     // use the instantiated loc
+        e = e->optimize(WANTvalue);
+    }
+    return e;
+}
+
+bool TemplateValueParameter::hasDefaultArg()
+{
+    return defaultValue != NULL;
+}
+
+/* ======================== TemplateTupleParameter ========================== */
+
+// variadic-parameter
+
+TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+}
+
+TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateTupleParameter::syntaxCopy()
+{
+    return new TemplateTupleParameter(loc, ident);
+}
+
+bool TemplateTupleParameter::declareParameter(Scope *sc)
+{
+    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+    Declaration *ad = new AliasDeclaration(loc, ident, ti);
+    return sc->insert(ad) != NULL;
+}
+
+bool TemplateTupleParameter::semantic(Scope *sc, TemplateParameters *parameters)
+{
+    return true;
+}
+
+MATCH TemplateTupleParameter::matchArg(Loc instLoc, Scope *sc, Objects *tiargs,
+        size_t i, TemplateParameters *parameters, Objects *dedtypes,
+        Declaration **psparam)
+{
+    /* 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 (Tuple *u = isTuple((*dedtypes)[i]))
+    {
+        // It has already been deduced
+        ovar = u;
+    }
+    else if (i + 1 == tiargs->dim && isTuple((*tiargs)[i]))
+        ovar = isTuple((*tiargs)[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[j] = (*tiargs)[i + j];
+        }
+    }
+    return matchArg(sc, ovar, i, parameters, dedtypes, psparam);
+}
+
+MATCH TemplateTupleParameter::matchArg(Scope *sc, RootObject *oarg,
+        size_t i, TemplateParameters *parameters, Objects *dedtypes,
+        Declaration **psparam)
+{
+    //printf("TemplateTupleParameter::matchArg('%s')\n", ident->toChars());
+    Tuple *ovar = isTuple(oarg);
+    if (!ovar)
+        return MATCHnomatch;
+    if ((*dedtypes)[i])
+    {
+        Tuple *tup = isTuple((*dedtypes)[i]);
+        if (!tup)
+            return MATCHnomatch;
+        if (!match(tup, ovar))
+            return MATCHnomatch;
+    }
+    (*dedtypes)[i] = ovar;
+
+    if (psparam)
+        *psparam = new TupleDeclaration(loc, ident, &ovar->objects);
+    return dependent ? MATCHexact : MATCHconvert;
+}
+
+
+void TemplateTupleParameter::print(RootObject *oarg, RootObject *oded)
+{
+    printf(" %s... [", ident->toChars());
+    Tuple *v = isTuple(oded);
+    assert(v);
+
+    //printf("|%d| ", v->objects.dim);
+    for (size_t i = 0; i < v->objects.dim; i++)
+    {
+        if (i)
+            printf(", ");
+
+        RootObject *o = v->objects[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::dummyArg()
+{
+    return NULL;
+}
+
+
+RootObject *TemplateTupleParameter::specialization()
+{
+    return NULL;
+}
+
+RootObject *TemplateTupleParameter::defaultArg(Loc instLoc, Scope *sc)
+{
+    return NULL;
+}
+
+bool TemplateTupleParameter::hasDefaultArg()
+{
+    return false;
+}
+
+/* ======================== 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->tinst = NULL;
+    this->tnext = NULL;
+    this->minst = NULL;
+    this->deferred = NULL;
+    this->memberOf = NULL;
+    this->argsym = NULL;
+    this->aliasdecl = NULL;
+    this->semantictiargsdone = false;
+    this->inuse = 0;
+    this->nest = 0;
+    this->havetempdecl = false;
+    this->enclosing = NULL;
+    this->gagged = false;
+    this->hash = 0;
+    this->fargs = 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->tinst = NULL;
+    this->tnext = NULL;
+    this->minst = NULL;
+    this->deferred = NULL;
+    this->memberOf = NULL;
+    this->argsym = NULL;
+    this->aliasdecl = NULL;
+    this->semantictiargsdone = true;
+    this->inuse = 0;
+    this->nest = 0;
+    this->havetempdecl = true;
+    this->enclosing = NULL;
+    this->gagged = false;
+    this->hash = 0;
+    this->fargs = NULL;
+
+    assert(tempdecl->_scope);
+}
+
+
+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)[i] = objectSyntaxCopy((*objs)[i]);
+    }
+    return a;
+}
+
+Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s)
+{
+    TemplateInstance *ti =
+        s ? (TemplateInstance *)s
+          : new TemplateInstance(loc, name);
+    ti->tiargs = arraySyntaxCopy(tiargs);
+    TemplateDeclaration *td;
+    if (inst && tempdecl && (td = tempdecl->isTemplateDeclaration()) != NULL)
+        td->ScopeDsymbol::syntaxCopy(ti);
+    else
+        ScopeDsymbol::syntaxCopy(ti);
+    return ti;
+}
+
+void TemplateInstance::semantic(Scope *sc)
+{
+    semantic(sc, NULL);
+}
+
+void TemplateInstance::expandMembers(Scope *sc2)
+{
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->setScope(sc2);
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->importAll(sc2);
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars());
+        //printf("test: enclosing = %d, sc2->parent = %s\n", enclosing, sc2->parent->toChars());
+//      if (enclosing)
+//          s->parent = sc->parent;
+        //printf("test3: enclosing = %d, s->parent = %s\n", enclosing, s->parent->toChars());
+        s->semantic(sc2);
+        //printf("test4: enclosing = %d, s->parent = %s\n", enclosing, s->parent->toChars());
+        Module::runDeferredSemantic();
+    }
+}
+
+void TemplateInstance::tryExpandMembers(Scope *sc2)
+{
+    static int nest;
+    // extracted to a function to allow windows SEH to work without destructors in the same function
+    //printf("%d\n", nest);
+    if (++nest > 500)
+    {
+        global.gag = 0;                 // ensure error message gets printed
+        error("recursive expansion");
+        fatal();
+    }
+
+    expandMembers(sc2);
+
+    nest--;
+}
+
+void TemplateInstance::trySemantic3(Scope *sc2)
+{
+    // extracted to a function to allow windows SEH to work without destructors in the same function
+    static int nest;
+    //printf("%d\n", nest);
+    if (++nest > 300)
+    {
+        global.gag = 0;            // ensure error message gets printed
+        error("recursive expansion");
+        fatal();
+    }
+    semantic3(sc2);
+
+    --nest;
+}
+
+void TemplateInstance::semantic(Scope *sc, Expressions *fargs)
+{
+    //printf("[%s] TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", loc.toChars(), toChars(), this, global.gag, sc);
+#if 0
+    for (Dsymbol *s = this; s; s = s->parent)
+    {
+        printf("\t%s\n", s->toChars());
+    }
+    printf("Scope\n");
+    for (Scope *scx = sc; scx; scx = scx->enclosing)
+    {
+        printf("\t%s parent %s\n", scx->_module ? scx->_module->toChars() : "null", scx->parent ? scx->parent->toChars() : "null");
+    }
+#endif
+
+#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 (semanticRun != PASSinit)
+    {
+#if LOG
+        printf("Recursive template expansion\n");
+#endif
+        Ungag ungag(global.gag);
+        if (!gagged)
+            global.gag = 0;
+        error(loc, "recursive template expansion");
+        if (gagged)
+            semanticRun = PASSinit;
+        else
+            inst = this;
+        errors = true;
+        return;
+    }
+
+    // Get the enclosing template instance from the scope tinst
+    tinst = sc->tinst;
+
+    // Get the instantiating module from the scope minst
+    minst = sc->minst;
+    // Bugzilla 10920: If the enclosing function is non-root symbol,
+    // this instance should be speculative.
+    if (!tinst && sc->func && sc->func->inNonRoot())
+    {
+        minst = NULL;
+    }
+
+    gagged = (global.gag > 0);
+
+    semanticRun = PASSsemantic;
+
+#if LOG
+    printf("\tdo semantic\n");
+#endif
+    /* Find template declaration first,
+     * then run semantic on each argument (place results in tiargs[]),
+     * last find most specialized template from overload list/set.
+     */
+    if (!findTempDecl(sc, NULL) ||
+        !semanticTiargs(sc) ||
+        !findBestMatch(sc, fargs))
+    {
+Lerror:
+        if (gagged)
+        {
+            // Bugzilla 13220: Rollback status for later semantic re-running.
+            semanticRun = PASSinit;
+        }
+        else
+            inst = this;
+        errors = true;
+        return;
+    }
+    TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+    assert(tempdecl);
+
+    // If tempdecl is a mixin, disallow it
+    if (tempdecl->ismixin)
+    {
+        error("mixin templates are not regular templates");
+        goto Lerror;
+    }
+
+    hasNestedArgs(tiargs, tempdecl->isstatic);
+    if (errors)
+        goto Lerror;
+
+    /* See if there is an existing TemplateInstantiation that already
+     * implements the typeargs. If so, just refer to that one instead.
+     */
+    inst = tempdecl->findExistingInstance(this, fargs);
+    TemplateInstance *errinst = NULL;
+    if (!inst)
+    {
+        // So, we need to implement 'this' instance.
+    }
+    else if (inst->gagged && !gagged && inst->errors)
+    {
+        // If the first instantiation had failed, re-run semantic,
+        // so that error messages are shown.
+        errinst = inst;
+    }
+    else
+    {
+        // It's a match
+        parent = inst->parent;
+        errors = inst->errors;
+
+        // If both this and the previous instantiation were gagged,
+        // use the number of errors that happened last time.
+        global.errors += errors;
+        global.gaggedErrors += errors;
+
+        // If the first instantiation was gagged, but this is not:
+        if (inst->gagged)
+        {
+            // It had succeeded, mark it is a non-gagged instantiation,
+            // and reuse it.
+            inst->gagged = gagged;
+        }
+
+        this->tnext = inst->tnext;
+        inst->tnext = this;
+
+        /* A module can have explicit template instance and its alias
+         * in module scope (e,g, `alias Base64 = Base64Impl!('+', '/');`).
+         * If the first instantiation 'inst' had happened in non-root module,
+         * compiler can assume that its instantiated code would be included
+         * in the separately compiled obj/lib file (e.g. phobos.lib).
+         *
+         * However, if 'this' second instantiation happened in root module,
+         * compiler might need to invoke its codegen (Bugzilla 2500 & 2644).
+         * But whole import graph is not determined until all semantic pass finished,
+         * so 'inst' should conservatively finish the semantic3 pass for the codegen.
+         */
+        if (minst && minst->isRoot() && !(inst->minst && inst->minst->isRoot()))
+        {
+            /* Swap the position of 'inst' and 'this' in the instantiation graph.
+             * Then, the primary instance `inst` will be changed to a root instance.
+             *
+             * Before:
+             *  non-root -> A!() -> B!()[inst] -> C!()
+             *                      |
+             *  root     -> D!() -> B!()[this]
+             *
+             * After:
+             *  non-root -> A!() -> B!()[this]
+             *                      |
+             *  root     -> D!() -> B!()[inst] -> C!()
+             */
+            Module *mi = minst;
+            TemplateInstance *ti = tinst;
+            minst = inst->minst;
+            tinst = inst->tinst;
+            inst->minst = mi;
+            inst->tinst = ti;
+
+            if (minst)  // if inst was not speculative
+            {
+                /* Add 'inst' once again to the root module members[], then the
+                 * instance members will get codegen chances.
+                 */
+                inst->appendToModuleMember();
+            }
+        }
+
+#if LOG
+        printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun);
+#endif
+        return;
+    }
+#if LOG
+    printf("\timplement template instance %s '%s'\n", tempdecl->parent->toChars(), toChars());
+    printf("\ttempdecl %s\n", tempdecl->toChars());
+#endif
+    unsigned errorsave = global.errors;
+
+    inst = this;
+    parent = enclosing ? enclosing : tempdecl->parent;
+    //printf("parent = '%s'\n", parent->kind());
+
+    TemplateInstance *tempdecl_instance_idx = tempdecl->addInstance(this);
+
+    //getIdent();
+
+    // Store the place we added it to in target_symbol_list(_idx) so we can
+    // remove it later if we encounter an error.
+    Dsymbols *target_symbol_list = appendToModuleMember();
+    size_t target_symbol_list_idx = target_symbol_list ? target_symbol_list->dim - 1 : 0;
+
+    // Copy the syntax trees from the TemplateDeclaration
+    members = Dsymbol::arraySyntaxCopy(tempdecl->members);
+
+    // resolve TemplateThisParameter
+    for (size_t i = 0; i < tempdecl->parameters->dim; i++)
+    {
+        if ((*tempdecl->parameters)[i]->isTemplateThisParameter() == NULL)
+            continue;
+        Type *t = isType((*tiargs)[i]);
+        assert(t);
+        if (StorageClass stc = ModToStc(t->mod))
+        {
+            //printf("t = %s, stc = x%llx\n", t->toChars(), stc);
+            Dsymbols *s = new Dsymbols();
+            s->push(new StorageClassDeclaration(stc, members));
+            members = s;
+        }
+        break;
+    }
+
+    // Create our own scope for the template parameters
+    Scope *scope = tempdecl->_scope;
+    if (tempdecl->semanticRun == PASSinit)
+    {
+        error("template instantiation %s forward references template declaration %s", toChars(), 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);
+    scope->tinst = this;
+    scope->minst = minst;
+    //scope->stc = 0;
+
+    // Declare each template parameter as an alias for the argument type
+    Scope *paramscope = scope->push();
+    paramscope->stc = 0;
+    paramscope->protection = Prot(PROTpublic);  // Bugzilla 14169: template parameters should be public
+    declareParameters(paramscope);
+    paramscope->pop();
+
+    // Add members of template instance to template instance symbol table
+//    parent = scope->scopesym;
+    symtab = new DsymbolTable();
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+#if LOG
+        printf("\t[%d] adding member '%s' %p kind %s to '%s'\n", i, s->toChars(), s, s->kind(), this->toChars());
+#endif
+        s->addMember(scope, this);
+    }
+#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, tempdecl->ident) && s)
+        {
+            //printf("tempdecl->ident = %s, s = '%s'\n", tempdecl->ident->toChars(), s->kind(), s->toPrettyChars());
+            //printf("setting aliasdecl\n");
+            aliasdecl = s;
+        }
+    }
+
+    /* If function template declaration
+     */
+    if (fargs && aliasdecl)
+    {
+        FuncDeclaration *fd = aliasdecl->isFuncDeclaration();
+        if (fd)
+        {
+            /* Transmit fargs to type so that TypeFunction::semantic() can
+             * resolve any "auto ref" storage classes.
+             */
+            TypeFunction *tf = (TypeFunction *)fd->type;
+            if (tf && tf->ty == Tfunction)
+                tf->fargs = fargs;
+        }
+    }
+
+    // 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("enclosing = %d, sc->parent = %s\n", enclosing, sc->parent->toChars());
+    sc2->parent = this;
+    sc2->tinst = this;
+    sc2->minst = minst;
+
+    tryExpandMembers(sc2);
+
+    semanticRun = PASSsemanticdone;
+
+    /* ConditionalDeclaration may introduce eponymous declaration,
+     * so we should find it once again after semantic.
+     */
+    if (members->dim)
+    {
+        Dsymbol *s;
+        if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s)
+        {
+            if (!aliasdecl || aliasdecl != s)
+            {
+                //printf("tempdecl->ident = %s, s = '%s'\n", tempdecl->ident->toChars(), s->kind(), s->toPrettyChars());
+                //printf("setting aliasdecl 2\n");
+                aliasdecl = s;
+            }
+        }
+    }
+
+    if (global.errors != errorsave)
+        goto Laftersemantic;
+
+    /* If any of the instantiation members didn't get semantic() run
+     * on them due to forward references, we cannot run semantic2()
+     * or semantic3() yet.
+     */
+    {
+    bool found_deferred_ad = false;
+    for (size_t i = 0; i < Module::deferred.dim; i++)
+    {
+        Dsymbol *sd = Module::deferred[i];
+        AggregateDeclaration *ad = sd->isAggregateDeclaration();
+        if (ad && ad->parent && ad->parent->isTemplateInstance())
+        {
+            //printf("deferred template aggregate: %s %s\n",
+            //        sd->parent->toChars(), sd->toChars());
+            found_deferred_ad = true;
+            if (ad->parent == this)
+            {
+                ad->deferred = this;
+                break;
+            }
+        }
+    }
+    if (found_deferred_ad || Module::deferred.dim)
+        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 (global.errors != errorsave)
+        goto Laftersemantic;
+
+    if ((sc->func || (sc->flags & SCOPEfullinst)) && !tinst)
+    {
+        /* If a template is instantiated inside function, the whole instantiation
+         * should be done at that position. But, immediate running semantic3 of
+         * dependent templates may cause unresolved forward reference (Bugzilla 9050).
+         * To avoid the issue, don't run semantic3 until semantic and semantic2 done.
+         */
+        TemplateInstances deferred;
+        this->deferred = &deferred;
+
+        //printf("Run semantic3 on %s\n", toChars());
+        trySemantic3(sc2);
+
+        for (size_t i = 0; i < deferred.dim; i++)
+        {
+            //printf("+ run deferred semantic3 on %s\n", deferred[i]->toChars());
+            deferred[i]->semantic3(NULL);
+        }
+
+        this->deferred = NULL;
+    }
+    else if (tinst)
+    {
+        bool doSemantic3 = false;
+        if (sc->func && aliasdecl && aliasdecl->toAlias()->isFuncDeclaration())
+        {
+            /* Template function instantiation should run semantic3 immediately
+             * for attribute inference.
+             */
+            trySemantic3(sc2);
+        }
+        else if (sc->func)
+        {
+            /* A lambda function in template arguments might capture the
+             * instantiated scope context. For the correct context inference,
+             * all instantiated functions should run the semantic3 immediately.
+             * See also compilable/test14973.d
+             */
+            for (size_t i = 0; i < tdtypes.dim; i++)
+            {
+                RootObject *oarg = tdtypes[i];
+                Dsymbol *s = getDsymbol(oarg);
+                if (!s)
+                    continue;
+
+                if (TemplateDeclaration *td = s->isTemplateDeclaration())
+                {
+                    if (!td->literal)
+                        continue;
+                    assert(td->members && td->members->dim == 1);
+                    s = (*td->members)[0];
+                }
+                if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
+                {
+                    if (fld->tok == TOKreserved)
+                    {
+                        doSemantic3 = true;
+                        break;
+                    }
+                }
+            }
+            //printf("[%s] %s doSemantic3 = %d\n", loc.toChars(), toChars(), doSemantic3);
+        }
+        if (doSemantic3)
+            trySemantic3(sc2);
+
+        TemplateInstance *ti = tinst;
+        int nest = 0;
+        while (ti && !ti->deferred && ti->tinst)
+        {
+            ti = ti->tinst;
+            if (++nest > 500)
+            {
+                global.gag = 0;            // ensure error message gets printed
+                error("recursive expansion");
+                fatal();
+            }
+        }
+        if (ti && ti->deferred)
+        {
+            //printf("deferred semantic3 of %p %s, ti = %s, ti->deferred = %p\n", this, toChars(), ti->toChars());
+            for (size_t i = 0; ; i++)
+            {
+                if (i == ti->deferred->dim)
+                {
+                    ti->deferred->push(this);
+                    break;
+                }
+                if ((*ti->deferred)[i] == this)
+                    break;
+            }
+        }
+    }
+
+    if (aliasdecl)
+    {
+        /* Bugzilla 13816: AliasDeclaration tries to resolve forward reference
+         * twice (See inuse check in AliasDeclaration::toAlias()). It's
+         * necessary to resolve mutual references of instantiated symbols, but
+         * it will left a true recursive alias in tuple declaration - an
+         * AliasDeclaration A refers TupleDeclaration B, and B contains A
+         * in its elements.  To correctly make it an error, we strictly need to
+         * resolve the alias of eponymous member.
+         */
+        aliasdecl = aliasdecl->toAlias2();
+    }
+
+  Laftersemantic:
+    sc2->pop();
+
+    scope->pop();
+
+    // Give additional context info if error occurred during instantiation
+    if (global.errors != errorsave)
+    {
+        if (!errors)
+        {
+            if (!tempdecl->literal)
+                error(loc, "error instantiating");
+            if (tinst)
+                tinst->printInstantiationTrace();
+        }
+        errors = true;
+        if (gagged)
+        {
+            // Errors are gagged, so remove the template instance from the
+            // instance/symbol lists we added it to and reset our state to
+            // finish clean and so we can try to instantiate it again later
+            // (see bugzilla 4302 and 6602).
+            tempdecl->removeInstance(tempdecl_instance_idx);
+            if (target_symbol_list)
+            {
+                // Because we added 'this' in the last position above, we
+                // should be able to remove it without messing other indices up.
+                assert((*target_symbol_list)[target_symbol_list_idx] == this);
+                target_symbol_list->remove(target_symbol_list_idx);
+                memberOf = NULL;                    // no longer a member
+            }
+            semanticRun = PASSinit;
+            inst = NULL;
+            symtab = NULL;
+        }
+    }
+    else if (errinst)
+    {
+        /* Bugzilla 14541: If the previous gagged instance had failed by
+         * circular references, currrent "error reproduction instantiation"
+         * might succeed, because of the difference of instantiated context.
+         * On such case, the cached error instance needs to be overridden by the
+         * succeeded instance.
+         */
+        //printf("replaceInstance()\n");
+        TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)tempdecl->instances, (void *)hash);
+        assert(tinstances);
+        for (size_t i = 0; i < tinstances->dim; i++)
+        {
+            TemplateInstance *ti = (*tinstances)[i];
+            if (ti == errinst)
+            {
+                (*tinstances)[i] = this;     // override
+                break;
+            }
+        }
+    }
+
+#if LOG
+    printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this);
+#endif
+}
+
+
+/**********************************************
+ * Find template declaration corresponding to template instance.
+ *
+ * Returns:
+ *      false if finding fails.
+ * Note:
+ *      This function is reentrant against error occurrence. If returns false,
+ *      any members of this object won't be modified, and repetition call will
+ *      reproduce same error.
+ */
+
+bool TemplateInstance::findTempDecl(Scope *sc, WithScopeSymbol **pwithsym)
+{
+    if (pwithsym)
+        *pwithsym = NULL;
+
+    if (havetempdecl)
+        return true;
+
+    //printf("TemplateInstance::findTempDecl() %s\n", toChars());
+    if (!tempdecl)
+    {
+        /* Given:
+         *    foo!( ... )
+         * figure out which TemplateDeclaration foo refers to.
+         */
+        Identifier *id = name;
+        Dsymbol *scopesym;
+        Dsymbol *s = sc->search(loc, id, &scopesym);
+        if (!s)
+        {
+            s = sc->search_correct(id);
+            if (s)
+                error("template '%s' is not defined, did you mean %s?", id->toChars(), s->toChars());
+            else
+                error("template '%s' is not defined", id->toChars());
+            return false;
+        }
+
+#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
+        if (pwithsym)
+            *pwithsym = 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->tempdecl && ti->tempdecl->ident == id)
+            {
+                /* 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)
+                 */
+                TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration();
+                assert(td);
+                if (td->overroot)       // if not start of overloaded list of TemplateDeclaration's
+                    td = td->overroot;  // then get the start
+                s = td;
+            }
+        }
+
+        if (!updateTempDecl(sc, s))
+        {
+            return false;
+        }
+    }
+    assert(tempdecl);
+
+  struct ParamFwdTi
+  {
+    static int fp(void *param, Dsymbol *s)
+    {
+        TemplateDeclaration *td = s->isTemplateDeclaration();
+        if (!td)
+            return 0;
+
+        TemplateInstance *ti = (TemplateInstance *)param;
+        if (td->semanticRun == PASSinit)
+        {
+            if (td->_scope)
+            {
+                // Try to fix forward reference. Ungag errors while doing so.
+                Ungag ungag = td->ungagSpeculative();
+                td->semantic(td->_scope);
+            }
+            if (td->semanticRun == PASSinit)
+            {
+                ti->error("%s forward references template declaration %s", ti->toChars(), td->toChars());
+                return 1;
+            }
+        }
+        return 0;
+    }
+  };
+    // Look for forward references
+    OverloadSet *tovers = tempdecl->isOverloadSet();
+    size_t overs_dim = tovers ? tovers->a.dim : 1;
+    for (size_t oi = 0; oi < overs_dim; oi++)
+    {
+        if (overloadApply(tovers ? tovers->a[oi] : tempdecl, (void *)this, &ParamFwdTi::fp))
+            return false;
+    }
+    return true;
+}
+
+/**********************************************
+ * Confirm s is a valid template, then store it.
+ * Input:
+ *      sc
+ *      s   candidate symbol of template. It may be:
+ *          TemplateDeclaration
+ *          FuncDeclaration with findTemplateDeclRoot() != NULL
+ *          OverloadSet which contains candidates
+ * Returns:
+ *      true if updating succeeds.
+ */
+
+bool TemplateInstance::updateTempDecl(Scope *sc, Dsymbol *s)
+{
+    if (s)
+    {
+        Identifier *id = name;
+        s = s->toAlias();
+
+        /* If an OverloadSet, look for a unique member that is a template declaration
+         */
+        OverloadSet *os = s->isOverloadSet();
+        if (os)
+        {
+            s = NULL;
+            for (size_t i = 0; i < os->a.dim; i++)
+            {
+                Dsymbol *s2 = os->a[i];
+                if (FuncDeclaration *f = s2->isFuncDeclaration())
+                    s2 = f->findTemplateDeclRoot();
+                else
+                    s2 = s2->isTemplateDeclaration();
+                if (s2)
+                {
+                    if (s)
+                    {
+                        tempdecl = os;
+                        return true;
+                    }
+                    s = s2;
+                }
+            }
+            if (!s)
+            {
+                error("template '%s' is not defined", id->toChars());
+                return false;
+            }
+        }
+
+        OverDeclaration *od = s->isOverDeclaration();
+        if (od)
+        {
+            tempdecl = od;  // TODO: more strict check
+            return true;
+        }
+
+        /* It should be a TemplateDeclaration, not some other symbol
+         */
+        if (FuncDeclaration *f = s->isFuncDeclaration())
+            tempdecl = f->findTemplateDeclRoot();
+        else
+            tempdecl = s->isTemplateDeclaration();
+        if (!tempdecl)
+        {
+            if (!s->parent && global.errors)
+                return false;
+            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 false;
+                }
+                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 == s->ident ||
+                 ti->toAlias()->ident == s->ident)
+                &&
+                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)
+                 */
+                TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration();
+                assert(td);
+                if (td->overroot)       // if not start of overloaded list of TemplateDeclaration's
+                    td = td->overroot;  // then get the start
+                tempdecl = td;
+            }
+            else
+            {
+                error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
+                return false;
+            }
+        }
+    }
+    return (tempdecl != NULL);
+}
+
+/**********************************
+ * Run semantic on the elements of tiargs.
+ * Input:
+ *      sc
+ * Returns:
+ *      false if one or more arguments have errors.
+ * Note:
+ *      This function is reentrant against error occurrence. If returns false,
+ *      all elements of tiargs won't be modified.
+ */
+
+bool TemplateInstance::semanticTiargs(Scope *sc)
+{
+    //printf("+TemplateInstance::semanticTiargs() %s\n", toChars());
+    if (semantictiargsdone)
+        return true;
+    if (semanticTiargs(loc, sc, tiargs, 0))
+    {
+        // cache the result iff semantic analysis succeeded entirely
+        semantictiargsdone = 1;
+        return true;
+    }
+    return false;
+}
+
+/**********************************
+ * Run semantic of tiargs as arguments of template.
+ * Input:
+ *      loc
+ *      sc
+ *      tiargs  array of template arguments
+ *      flags   1: replace const variables with their initializers
+ *              2: don't devolve Parameter to Type
+ * Returns:
+ *      false if one or more arguments have errors.
+ */
+
+bool 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 true;
+    bool err = false;
+    for (size_t j = 0; j < tiargs->dim; j++)
+    {
+        RootObject *o = (*tiargs)[j];
+        Type *ta = isType(o);
+        Expression *ea = isExpression(o);
+        Dsymbol *sa = isDsymbol(o);
+
+        //printf("1: (*tiargs)[%d] = %p, s=%p, v=%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) goto Lexpr;
+            if (sa) goto Ldsym;
+            if (ta == NULL)
+            {
+                assert(global.errors);
+                ta = Type::terror;
+            }
+
+        Ltype:
+            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++)
+                    {
+                        Parameter *arg = (*tt->arguments)[i];
+                        if (flags & 2 && arg->ident)
+                            tiargs->insert(j + i, arg);
+                        else
+                            tiargs->insert(j + i, arg->type);
+                    }
+                }
+                j--;
+                continue;
+            }
+            if (ta->ty == Terror)
+            {
+                err = true;
+                continue;
+            }
+            (*tiargs)[j] = ta->merge2();
+        }
+        else if (ea)
+        {
+        Lexpr:
+            //printf("+[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars());
+            if (flags & 1) // only used by __traits
+            {
+                ea = ::semantic(ea, sc);
+
+                // must not interpret the args, excepting template parameters
+                if (ea->op != TOKvar ||
+                    (((VarExp *)ea)->var->storage_class & STCtemplateparameter))
+                {
+                    ea = ea->optimize(WANTvalue);
+                }
+            }
+            else
+            {
+                sc = sc->startCTFE();
+                ea = ::semantic(ea, sc);
+                sc = sc->endCTFE();
+
+                if (ea->op == TOKvar)
+                {
+                    /* 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().
+                     */
+                }
+                else if (definitelyValueParameter(ea))
+                {
+                    if (ea->checkValue())   // check void expression
+                        ea = new ErrorExp();
+                    unsigned int olderrs = global.errors;
+                    ea = ea->ctfeInterpret();
+                    if (global.errors != olderrs)
+                        ea = new ErrorExp();
+                }
+            }
+            //printf("-[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars());
+            if (ea->op == TOKtuple)
+            {
+                // Expand tuple
+                TupleExp *te = (TupleExp *)ea;
+                size_t dim = te->exps->dim;
+                tiargs->remove(j);
+                if (dim)
+                {
+                    tiargs->reserve(dim);
+                    for (size_t i = 0; i < dim; i++)
+                        tiargs->insert(j + i, (*te->exps)[i]);
+                }
+                j--;
+                continue;
+            }
+            if (ea->op == TOKerror)
+            {
+                err = true;
+                continue;
+            }
+            (*tiargs)[j] = ea;
+
+            if (ea->op == TOKtype)
+            {
+                ta = ea->type;
+                goto Ltype;
+            }
+            if (ea->op == TOKscope)
+            {
+                sa = ((ScopeExp *)ea)->sds;
+                goto Ldsym;
+            }
+            if (ea->op == TOKfunction)
+            {
+                FuncExp *fe = (FuncExp *)ea;
+                /* A function literal, that is passed to template and
+                 * already semanticed as function pointer, never requires
+                 * outer frame. So convert it to global function is valid.
+                 */
+                if (fe->fd->tok == TOKreserved && fe->type->ty == Tpointer)
+                {
+                    // change to non-nested
+                    fe->fd->tok = TOKfunction;
+                    fe->fd->vthis = NULL;
+                }
+                else if (fe->td)
+                {
+                    /* If template argument is a template lambda,
+                     * get template declaration itself. */
+                    //sa = fe->td;
+                    //goto Ldsym;
+                }
+            }
+            if (ea->op == TOKdotvar)
+            {
+                // translate expression to dsymbol.
+                sa = ((DotVarExp *)ea)->var;
+                goto Ldsym;
+            }
+            if (ea->op == TOKtemplate)
+            {
+                sa = ((TemplateExp *)ea)->td;
+                goto Ldsym;
+            }
+            if (ea->op == TOKdottd)
+            {
+                // translate expression to dsymbol.
+                sa = ((DotTemplateExp *)ea)->td;
+                goto Ldsym;
+            }
+        }
+        else if (sa)
+        {
+        Ldsym:
+            //printf("dsym %s %s\n", sa->kind(), sa->toChars());
+            if (sa->errors)
+            {
+                err = true;
+                continue;
+            }
+
+            TupleDeclaration *d = sa->toAlias()->isTupleDeclaration();
+            if (d)
+            {
+                // Expand tuple
+                tiargs->remove(j);
+                tiargs->insert(j, d->objects);
+                j--;
+                continue;
+            }
+            if (FuncAliasDeclaration *fa = sa->isFuncAliasDeclaration())
+            {
+                FuncDeclaration *f = fa->toAliasFunc();
+                if (!fa->hasOverloads && f->isUnique())
+                {
+                    // Strip FuncAlias only when the aliased function
+                    // does not have any overloads.
+                    sa = f;
+                }
+            }
+            (*tiargs)[j] = sa;
+
+            TemplateDeclaration *td = sa->isTemplateDeclaration();
+            if (td && td->semanticRun == PASSinit && td->literal)
+            {
+                td->semantic(sc);
+            }
+            FuncDeclaration *fd = sa->isFuncDeclaration();
+            if (fd)
+                fd->functionSemantic();
+        }
+        else if (isParameter(o))
+        {
+        }
+        else
+        {
+            assert(0);
+        }
+        //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
+    }
+#if 0
+    printf("-TemplateInstance::semanticTiargs()\n");
+    for (size_t j = 0; j < tiargs->dim; j++)
+    {
+        RootObject *o = (*tiargs)[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
+    return !err;
+}
+
+bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
+{
+    if (havetempdecl)
+    {
+        TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+        assert(tempdecl);
+        assert(tempdecl->_scope);
+        // Deduce tdtypes
+        tdtypes.setDim(tempdecl->parameters->dim);
+        if (!tempdecl->matchWithInstance(sc, this, &tdtypes, fargs, 2))
+        {
+            error("incompatible arguments for template instantiation");
+            return false;
+        }
+        // TODO: Normalizing tiargs for bugzilla 7469 is necessary?
+        return true;
+    }
+
+#if LOG
+    printf("TemplateInstance::findBestMatch()\n");
+#endif
+    unsigned errs = global.errors;
+
+  struct ParamBest
+  {
+    // context
+    Scope *sc;
+    TemplateInstance *ti;
+    Objects dedtypes;
+    // result
+    TemplateDeclaration *td_best;
+    TemplateDeclaration *td_ambig;
+    MATCH m_best;
+
+    static int fp(void *param, Dsymbol *s)
+    {
+        return ((ParamBest *)param)->fp(s);
+    }
+    int fp(Dsymbol *s)
+    {
+        TemplateDeclaration *td = s->isTemplateDeclaration();
+        if (!td)
+            return 0;
+
+        if (td == td_best)          // skip duplicates
+            return 0;
+
+        //printf("td = %s\n", td->toPrettyChars());
+
+        // If more arguments than parameters,
+        // then this is no match.
+        if (td->parameters->dim < ti->tiargs->dim)
+        {
+            if (!td->isVariadic())
+                return 0;
+        }
+
+        dedtypes.setDim(td->parameters->dim);
+        dedtypes.zero();
+        assert(td->semanticRun != PASSinit);
+        MATCH m = td->matchWithInstance(sc, ti, &dedtypes, ti->fargs, 0);
+        //printf("matchWithInstance = %d\n", m);
+        if (m <= MATCHnomatch)                 // no match at all
+            return 0;
+
+        if (m < m_best) goto Ltd_best;
+        if (m > m_best) goto Ltd;
+
+        {
+        // Disambiguate by picking the most specialized TemplateDeclaration
+        MATCH c1 = td->leastAsSpecialized(sc, td_best, ti->fargs);
+        MATCH c2 = td_best->leastAsSpecialized(sc, td, ti->fargs);
+        //printf("c1 = %d, c2 = %d\n", c1, c2);
+        if (c1 > c2) goto Ltd;
+        if (c1 < c2) goto Ltd_best;
+        }
+
+        td_ambig = td;
+        return 0;
+
+      Ltd_best:         // td_best is the best match so far
+        td_ambig = NULL;
+        return 0;
+
+      Ltd:              // td is the new best match
+        td_ambig = NULL;
+        td_best = td;
+        m_best = m;
+        ti->tdtypes.setDim(dedtypes.dim);
+        memcpy(ti->tdtypes.tdata(), dedtypes.tdata(), ti->tdtypes.dim * sizeof(void *));
+        return 0;
+    }
+  };
+    ParamBest p;
+    // context
+    p.ti = this;
+    p.sc = sc;
+
+    /* Since there can be multiple TemplateDeclaration's with the same
+     * name, look for the best match.
+     */
+    TemplateDeclaration *td_last = NULL;
+
+    OverloadSet *tovers = tempdecl->isOverloadSet();
+    size_t overs_dim = tovers ? tovers->a.dim : 1;
+    for (size_t oi = 0; oi < overs_dim; oi++)
+    {
+        // result
+        p.td_best  = NULL;
+        p.td_ambig = NULL;
+        p.m_best   = MATCHnomatch;
+        overloadApply(tovers ? tovers->a[oi] : tempdecl, &p, &ParamBest::fp);
+
+        if (p.td_ambig)
+        {
+            ::error(loc, "%s %s.%s matches more than one template declaration:\n%s:     %s\nand\n%s:     %s",
+                    p.td_best->kind(), p.td_best->parent->toPrettyChars(), p.td_best->ident->toChars(),
+                    p.td_best->loc.toChars() , p.td_best->toChars(),
+                    p.td_ambig->loc.toChars(), p.td_ambig->toChars());
+            return false;
+        }
+        if (p.td_best)
+        {
+            if (!td_last)
+                td_last = p.td_best;
+            else if (td_last != p.td_best)
+            {
+                ScopeDsymbol::multiplyDefined(loc, td_last, p.td_best);
+                return false;
+            }
+        }
+    }
+
+    if (td_last)
+    {
+        /* Bugzilla 7469: Normalize tiargs by using corresponding deduced
+         * template value parameters and tuples for the correct mangling.
+         *
+         * By doing this before hasNestedArgs, CTFEable local variable will be
+         * accepted as a value parameter. For example:
+         *
+         *  void foo() {
+         *    struct S(int n) {}   // non-global template
+         *    const int num = 1;   // CTFEable local variable
+         *    S!num s;             // S!1 is instantiated, not S!num
+         *  }
+         */
+        size_t dim = td_last->parameters->dim - (td_last->isVariadic() ? 1 : 0);
+        for (size_t i = 0; i < dim; i++)
+        {
+            if (tiargs->dim <= i)
+                tiargs->push(tdtypes[i]);
+            assert(i < tiargs->dim);
+
+            TemplateValueParameter *tvp = (*td_last->parameters)[i]->isTemplateValueParameter();
+            if (!tvp)
+                continue;
+            assert(tdtypes[i]);
+            // tdtypes[i] is already normalized to the required type in matchArg
+
+            (*tiargs)[i] = tdtypes[i];
+        }
+        if (td_last->isVariadic() && tiargs->dim == dim && tdtypes[dim])
+        {
+            Tuple *va = isTuple(tdtypes[dim]);
+            assert(va);
+            for (size_t i = 0; i < va->objects.dim; i++)
+                tiargs->push(va->objects[i]);
+        }
+    }
+    else if (errors && inst)
+    {
+        // instantiation was failed with error reporting
+        assert(global.errors);
+        return false;
+    }
+    else
+    {
+        TemplateDeclaration *tdecl = tempdecl->isTemplateDeclaration();
+
+        if (errs != global.errors)
+            errorSupplemental(loc, "while looking for match for %s", toChars());
+        else if (tdecl && !tdecl->overnext)
+        {
+            // Only one template, so we can give better error message
+            error("does not match template declaration %s", tdecl->toChars());
+        }
+        else
+            ::error(loc, "%s %s.%s does not match any template declaration",
+                    tempdecl->kind(), tempdecl->parent->toPrettyChars(), tempdecl->ident->toChars());
+        return false;
+    }
+
+    /* The best match is td_last
+     */
+    tempdecl = td_last;
+
+#if LOG
+    printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars());
+#endif
+    return (errs == global.errors);
+}
+
+/*****************************************************
+ * Determine if template instance is really a template function,
+ * and that template function needs to infer types from the function
+ * arguments.
+ *
+ * Like findBestMatch, iterate possible template candidates,
+ * but just looks only the necessity of type inference.
+ */
+
+bool TemplateInstance::needsTypeInference(Scope *sc, int flag)
+{
+    //printf("TemplateInstance::needsTypeInference() %s\n", toChars());
+    if (semanticRun != PASSinit)
+        return false;
+
+  struct ParamNeedsInf
+  {
+    // context
+    Scope *sc;
+    TemplateInstance *ti;
+    int flag;
+    // result
+    Objects dedtypes;
+    size_t count;
+
+    static int fp(void *param, Dsymbol *s)
+    {
+        return ((ParamNeedsInf *)param)->fp(s);
+    }
+    int fp(Dsymbol *s)
+    {
+        TemplateDeclaration *td = s->isTemplateDeclaration();
+        if (!td)
+        {
+            return 0;
+        }
+
+        /* If any of the overloaded template declarations need inference,
+         * then return true
+         */
+        FuncDeclaration *fd;
+        if (!td->onemember)
+            return 0;
+        if (TemplateDeclaration *td2 = td->onemember->isTemplateDeclaration())
+        {
+            if (!td2->onemember || !td2->onemember->isFuncDeclaration())
+                return 0;
+            if (ti->tiargs->dim > td->parameters->dim && !td->isVariadic())
+                return 0;
+            return 1;
+        }
+        if ((fd = td->onemember->isFuncDeclaration()) == NULL ||
+            fd->type->ty != Tfunction)
+        {
+            return 0;
+        }
+
+        for (size_t i = 0; i < td->parameters->dim; i++)
+        {
+            if ((*td->parameters)[i]->isTemplateThisParameter())
+                return 1;
+        }
+
+        /* Determine if the instance arguments, tiargs, are all that is necessary
+         * to instantiate the template.
+         */
+        //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, ti->tiargs->dim);
+        TypeFunction *tf = (TypeFunction *)fd->type;
+        if (size_t dim = Parameter::dim(tf->parameters))
+        {
+            TemplateParameter *tp = td->isVariadic();
+            if (tp && td->parameters->dim > 1)
+                return 1;
+
+            if (!tp && ti->tiargs->dim < td->parameters->dim)
+            {
+                // Can remain tiargs be filled by default arguments?
+                for (size_t i = ti->tiargs->dim; i < td->parameters->dim; i++)
+                {
+                    if (!(*td->parameters)[i]->hasDefaultArg())
+                        return 1;
+                }
+            }
+
+            for (size_t i = 0; i < dim; i++)
+            {
+                // 'auto ref' needs inference.
+                if (Parameter::getNth(tf->parameters, i)->storageClass & STCauto)
+                    return 1;
+            }
+        }
+
+        if (!flag)
+        {
+            /* Calculate the need for overload resolution.
+             * When only one template can match with tiargs, inference is not necessary.
+             */
+            dedtypes.setDim(td->parameters->dim);
+            dedtypes.zero();
+            if (td->semanticRun == PASSinit)
+            {
+                if (td->_scope)
+                {
+                    // Try to fix forward reference. Ungag errors while doing so.
+                    Ungag ungag = td->ungagSpeculative();
+                    td->semantic(td->_scope);
+                }
+                if (td->semanticRun == PASSinit)
+                {
+                    ti->error("%s forward references template declaration %s", ti->toChars(), td->toChars());
+                    return 1;
+                }
+            }
+            assert(td->semanticRun != PASSinit);
+            MATCH m = td->matchWithInstance(sc, ti, &dedtypes, NULL, 0);
+            if (m <= MATCHnomatch)
+                return 0;
+        }
+
+        /* If there is more than one function template which matches, we may
+         * need type inference (see Bugzilla 4430)
+         */
+        if (++count > 1)
+            return 1;
+
+        return 0;
+    }
+  };
+    ParamNeedsInf p;
+    // context
+    p.ti    = this;
+    p.sc    = sc;
+    p.flag  = flag;
+    // result
+    p.count = 0;
+
+    OverloadSet *tovers = tempdecl->isOverloadSet();
+    size_t overs_dim = tovers ? tovers->a.dim : 1;
+    unsigned olderrs = global.errors;
+    for (size_t oi = 0; oi < overs_dim; oi++)
+    {
+        if (overloadApply(tovers ? tovers->a[oi] : tempdecl, &p, &ParamNeedsInf::fp))
+            return true;
+    }
+    if (olderrs != global.errors)
+    {
+        if (!global.gag)
+        {
+            errorSupplemental(loc, "while looking for match for %s", toChars());
+            semanticRun = PASSsemanticdone;
+            inst = this;
+        }
+        errors = true;
+    }
+    //printf("false\n");
+    return false;
+}
+
+
+/*****************************************
+ * Determines if a TemplateInstance will need a nested
+ * generation of the TemplateDeclaration.
+ * Sets enclosing property if so, and returns != 0;
+ */
+
+bool TemplateInstance::hasNestedArgs(Objects *args, bool isstatic)
+{
+    int nested = 0;
+    //printf("TemplateInstance::hasNestedArgs('%s')\n", tempdecl->ident->toChars());
+
+#if 0
+    if (!enclosing)
+    {
+        if (TemplateInstance *ti = tempdecl->isInstantiated())
+            enclosing = ti->enclosing;
+    }
+#endif
+
+    /* 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++)
+    {
+        RootObject *o = (*args)[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 == TOKthis)
+            {
+                sa = ((ThisExp *)ea)->var;
+                goto Lsa;
+            }
+            if (ea->op == TOKfunction)
+            {
+                if (((FuncExp *)ea)->td)
+                    sa = ((FuncExp *)ea)->td;
+                else
+                    sa = ((FuncExp *)ea)->fd;
+                goto Lsa;
+            }
+            // Emulate Expression::toMangleBuffer call that had exist in TemplateInstance::genIdent.
+            if (ea->op != TOKint64 &&
+                ea->op != TOKfloat64 &&
+                ea->op != TOKcomplex80 &&
+                ea->op != TOKnull &&
+                ea->op != TOKstring &&
+                ea->op != TOKarrayliteral &&
+                ea->op != TOKassocarrayliteral &&
+                ea->op != TOKstructliteral)
+            {
+                ea->error("expression %s is not a valid template value argument", ea->toChars());
+                errors = true;
+            }
+        }
+        else if (sa)
+        {
+          Lsa:
+            sa = sa->toAlias();
+            TemplateDeclaration *td = sa->isTemplateDeclaration();
+            if (td)
+            {
+                TemplateInstance *ti = sa->toParent()->isTemplateInstance();
+                if (ti && ti->enclosing)
+                    sa = ti;
+            }
+            TemplateInstance *ti = sa->isTemplateInstance();
+            Declaration *d = sa->isDeclaration();
+            if ((td && td->literal) ||
+                (ti && ti->enclosing) ||
+                (d && !d->isDataseg() &&
+                 !(d->storage_class & STCmanifest) &&
+                 (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) &&
+                 !isTemplateMixin()
+                ))
+            {
+                // if module level template
+                if (isstatic)
+                {
+                    Dsymbol *dparent = sa->toParent2();
+                    if (!enclosing)
+                        enclosing = dparent;
+                    else if (enclosing != dparent)
+                    {
+                        /* Select the more deeply nested of the two.
+                         * Error if one is not nested inside the other.
+                         */
+                        for (Dsymbol *p = enclosing; p; p = p->parent)
+                        {
+                            if (p == dparent)
+                                goto L1;        // enclosing is most nested
+                        }
+                        for (Dsymbol *p = dparent; p; p = p->parent)
+                        {
+                            if (p == enclosing)
+                            {
+                                enclosing = dparent;
+                                goto L1;        // dparent is most nested
+                            }
+                        }
+                        error("%s is nested in both %s and %s",
+                                toChars(), enclosing->toChars(), dparent->toChars());
+                        errors = true;
+                    }
+                  L1:
+                    //printf("\tnested inside %s\n", enclosing->toChars());
+                    nested |= 1;
+                }
+                else
+                {
+                    error("cannot use local '%s' as parameter to non-global template %s", sa->toChars(), tempdecl->toChars());
+                    errors = true;
+                }
+            }
+        }
+        else if (va)
+        {
+            nested |= (int)hasNestedArgs(&va->objects, isstatic);
+        }
+    }
+    //printf("-TemplateInstance::hasNestedArgs('%s') = %d\n", tempdecl->ident->toChars(), nested);
+    return nested != 0;
+}
+
+/*****************************************
+ * Append 'this' to the specific module members[]
+ */
+Dsymbols *TemplateInstance::appendToModuleMember()
+{
+    Module *mi = minst;     // instantiated -> inserted module
+
+    if (global.params.useUnitTests ||
+        global.params.debuglevel)
+    {
+        // Turn all non-root instances to speculative
+        if (mi && !mi->isRoot())
+            mi = NULL;
+    }
+
+    //printf("%s->appendToModuleMember() enclosing = %s mi = %s\n",
+    //    toPrettyChars(),
+    //    enclosing ? enclosing->toPrettyChars() : NULL,
+    //    mi ? mi->toPrettyChars() : NULL);
+    if (!mi || mi->isRoot())
+    {
+        /* If the instantiated module is speculative or root, insert to the
+         * member of a root module. Then:
+         *  - semantic3 pass will get called on the instance members.
+         *  - codegen pass will get a selection chance to do/skip it.
+         */
+
+        struct N
+        {
+            static Dsymbol *getStrictEnclosing(TemplateInstance *ti)
+            {
+                do
+                {
+                    if (ti->enclosing)
+                        return ti->enclosing;
+                    ti = ti->tempdecl->isInstantiated();
+                }
+                while (ti);
+                return NULL;
+            }
+        };
+        Dsymbol *enc = N::getStrictEnclosing(this);
+
+        // insert target is made stable by using the module
+        // where tempdecl is declared.
+        mi = (enc ? enc : tempdecl)->getModule();
+        if (!mi->isRoot())
+            mi = mi->importedFrom;
+        assert(mi->isRoot());
+    }
+    else
+    {
+        /* If the instantiated module is non-root, insert to the member of the
+         * non-root module. Then:
+         *  - semantic3 pass won't be called on the instance.
+         *  - codegen pass won't reach to the instance.
+         */
+    }
+    //printf("\t--> mi = %s\n", mi->toPrettyChars());
+
+    if (memberOf == mi)     // already a member
+    {
+#ifdef DEBUG
+        Dsymbols *a = mi->members;
+        for (size_t i = 0; 1; i++)
+        {
+            assert(i != a->dim);
+            if (this == (*a)[i])
+                break;
+        }
+#endif
+        return NULL;
+    }
+
+    Dsymbols *a = mi->members;
+    a->push(this);
+    memberOf = mi;
+    if (mi->semanticRun >= PASSsemantic2done && mi->isRoot())
+        Module::addDeferredSemantic2(this);
+    if (mi->semanticRun >= PASSsemantic3done && mi->isRoot())
+        Module::addDeferredSemantic3(this);
+    return a;
+}
+
+/****************************************
+ * 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(Objects *args)
+{
+    TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+    assert(tempdecl);
+
+    //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars());
+    OutBuffer buf;
+    const char *id = tempdecl->ident->toChars();
+    if (!members)
+    {
+        // Use "__U" for the symbols declared inside template constraint.
+        buf.printf("__U%llu%s", (ulonglong)strlen(id), id);
+    }
+    else
+        buf.printf("__T%llu%s", (ulonglong)strlen(id), id);
+    size_t nparams = tempdecl->parameters->dim - (tempdecl->isVariadic() ? 1 : 0);
+    for (size_t i = 0; i < args->dim; i++)
+    {
+        RootObject *o = (*args)[i];
+        Type *ta = isType(o);
+        Expression *ea = isExpression(o);
+        Dsymbol *sa = isDsymbol(o);
+        Tuple *va = isTuple(o);
+        //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
+        if (i < nparams && (*tempdecl->parameters)[i]->specialization())
+            buf.writeByte('H');     // Bugzilla 6574
+        if (ta)
+        {
+            buf.writeByte('T');
+            if (ta->deco)
+                buf.writestring(ta->deco);
+            else
+            {
+#ifdef DEBUG
+                if (!global.errors)
+                    printf("ta = %d, %s\n", ta->ty, ta->toChars());
+#endif
+                assert(global.errors);
+            }
+        }
+        else if (ea)
+        {
+            // Don't interpret it yet, it might actually be an alias template parameter.
+            // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
+            const bool keepLvalue = true;
+            ea = ea->optimize(WANTvalue, keepLvalue);
+            if (ea->op == TOKvar)
+            {
+                sa = ((VarExp *)ea)->var;
+                ea = NULL;
+                goto Lsa;
+            }
+            if (ea->op == TOKthis)
+            {
+                sa = ((ThisExp *)ea)->var;
+                ea = NULL;
+                goto Lsa;
+            }
+            if (ea->op == TOKfunction)
+            {
+                if (((FuncExp *)ea)->td)
+                    sa = ((FuncExp *)ea)->td;
+                else
+                    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;
+            }
+            // Now that we know it is not an alias, we MUST obtain a value
+            unsigned olderr = global.errors;
+            ea = ea->ctfeInterpret();
+            if (ea->op == TOKerror || olderr != global.errors)
+                continue;
+
+            /* Use deco that matches what it would be for a function parameter
+             */
+            buf.writestring(ea->type->deco);
+            mangleToBuffer(ea, &buf);
+        }
+        else if (sa)
+        {
+          Lsa:
+            buf.writeByte('S');
+            sa = sa->toAlias();
+            Declaration *d = sa->isDeclaration();
+            if (d && (!d->type || !d->type->deco))
+            {
+                error("forward reference of %s %s", d->kind(), d->toChars());
+                continue;
+            }
+
+            OutBuffer bufsa;
+            mangleToBuffer(sa, &bufsa);
+            const char *s = bufsa.extractString();
+
+            /* Bugzilla 3043: if the first character of s is a digit this
+             * causes ambiguity issues because the digits of the two numbers are adjacent.
+             * Current demanglers resolve this by trying various places to separate the
+             * numbers until one gets a successful demangle.
+             * Unfortunately, fixing this ambiguity will break existing binary
+             * compatibility and the demanglers, so we'll leave it as is.
+             */
+            buf.printf("%u%s", (unsigned)strlen(s), s);
+        }
+        else if (va)
+        {
+            assert(i + 1 == args->dim);         // must be last one
+            args = &va->objects;
+            i = -(size_t)1;
+        }
+        else
+            assert(0);
+    }
+    buf.writeByte('Z');
+    id = buf.peekString();
+    //printf("\tgenIdent = %s\n", id);
+    return Identifier::idPool(id);
+}
+
+/*************************************
+ * Lazily generate identifier for template instance.
+ * This is because 75% of the ident's are never needed.
+ */
+
+Identifier *TemplateInstance::getIdent()
+{
+    if (!ident && inst && !errors)
+        ident = genIdent(tiargs);         // need an identifier for name mangling purposes.
+    return ident;
+}
+
+/****************************************************
+ * Declare parameters of template instance, initialize them with the
+ * template instance arguments.
+ */
+
+void TemplateInstance::declareParameters(Scope *sc)
+{
+    TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+    assert(tempdecl);
+
+    //printf("TemplateInstance::declareParameters()\n");
+    for (size_t i = 0; i < tdtypes.dim; i++)
+    {
+        TemplateParameter *tp = (*tempdecl->parameters)[i];
+        //RootObject *o = (*tiargs)[i];
+        RootObject *o = tdtypes[i];          // initializer for tp
+
+        //printf("\ttdtypes[%d] = %p\n", i, o);
+        tempdecl->declareParameter(sc, tp, o);
+    }
+}
+
+void TemplateInstance::semantic2(Scope *sc)
+{
+    if (semanticRun >= PASSsemantic2)
+        return;
+    semanticRun = PASSsemantic2;
+#if LOG
+    printf("+TemplateInstance::semantic2('%s')\n", toChars());
+#endif
+    if (!errors && members)
+    {
+        TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+        assert(tempdecl);
+
+        sc = tempdecl->_scope;
+        assert(sc);
+        sc = sc->push(argsym);
+        sc = sc->push(this);
+        sc->tinst = this;
+        sc->minst = minst;
+
+        int needGagging = (gagged && !global.gag);
+        unsigned int olderrors = global.errors;
+        int oldGaggedErrors = -1;       // dead-store to prevent spurious warning
+        if (needGagging)
+            oldGaggedErrors = global.startGagging();
+
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+#if LOG
+printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind());
+#endif
+            s->semantic2(sc);
+            if (gagged && global.errors != olderrors)
+                break;
+        }
+
+        if (global.errors != olderrors)
+        {
+            if (!errors)
+            {
+                if (!tempdecl->literal)
+                    error(loc, "error instantiating");
+                if (tinst)
+                    tinst->printInstantiationTrace();
+            }
+            errors = true;
+        }
+        if (needGagging)
+            global.endGagging(oldGaggedErrors);
+
+        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'), semanticRun = %d\n", toChars(), semanticRun);
+#endif
+//if (toChars()[0] == 'D') *(char*)0=0;
+    if (semanticRun >= PASSsemantic3)
+        return;
+    semanticRun = PASSsemantic3;
+    if (!errors && members)
+    {
+        TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+        assert(tempdecl);
+
+        sc = tempdecl->_scope;
+        sc = sc->push(argsym);
+        sc = sc->push(this);
+        sc->tinst = this;
+        sc->minst = minst;
+
+        int needGagging = (gagged && !global.gag);
+        unsigned int olderrors = global.errors;
+        int oldGaggedErrors = -1;       // dead-store to prevent spurious warning
+        /* If this is a gagged instantiation, gag errors.
+         * Future optimisation: If the results are actually needed, errors
+         * would already be gagged, so we don't really need to run semantic
+         * on the members.
+         */
+        if (needGagging)
+            oldGaggedErrors = global.startGagging();
+
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            s->semantic3(sc);
+            if (gagged && global.errors != olderrors)
+                break;
+        }
+
+        if (global.errors != olderrors)
+        {
+            if (!errors)
+            {
+                if (!tempdecl->literal)
+                    error(loc, "error instantiating");
+                if (tinst)
+                    tinst->printInstantiationTrace();
+            }
+            errors = true;
+        }
+        if (needGagging)
+            global.endGagging(oldGaggedErrors);
+
+        sc = sc->pop();
+        sc->pop();
+    }
+}
+
+/**************************************
+ * Given an error instantiating the TemplateInstance,
+ * give the nested TemplateInstance instantiations that got
+ * us here. Those are a list threaded into the nested scopes.
+ */
+void TemplateInstance::printInstantiationTrace()
+{
+    if (global.gag)
+        return;
+
+    const unsigned max_shown = 6;
+    const char format[] = "instantiated from here: %s";
+
+    // determine instantiation depth and number of recursive instantiations
+    int n_instantiations = 1;
+    int n_totalrecursions = 0;
+    for (TemplateInstance *cur = this; cur; cur = cur->tinst)
+    {
+        ++n_instantiations;
+        // If two instantiations use the same declaration, they are recursive.
+        // (this works even if they are instantiated from different places in the
+        // same template).
+        // In principle, we could also check for multiple-template recursion, but it's
+        // probably not worthwhile.
+        if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl
+            && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc))
+            ++n_totalrecursions;
+    }
+
+    // show full trace only if it's short or verbose is on
+    if (n_instantiations <= max_shown || global.params.verbose)
+    {
+        for (TemplateInstance *cur = this; cur; cur = cur->tinst)
+        {
+            cur->errors = true;
+            errorSupplemental(cur->loc, format, cur->toChars());
+        }
+    }
+    else if (n_instantiations - n_totalrecursions <= max_shown)
+    {
+        // By collapsing recursive instantiations into a single line,
+        // we can stay under the limit.
+        int recursionDepth=0;
+        for (TemplateInstance *cur = this; cur; cur = cur->tinst)
+        {
+            cur->errors = true;
+            if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl
+                    && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc))
+            {
+                ++recursionDepth;
+            }
+            else
+            {
+                if (recursionDepth)
+                    errorSupplemental(cur->loc, "%d recursive instantiations from here: %s", recursionDepth+2, cur->toChars());
+                else
+                    errorSupplemental(cur->loc, format, cur->toChars());
+                recursionDepth = 0;
+            }
+        }
+    }
+    else
+    {
+        // Even after collapsing the recursions, the depth is too deep.
+        // Just display the first few and last few instantiations.
+        unsigned i = 0;
+        for (TemplateInstance *cur = this; cur; cur = cur->tinst)
+        {
+            cur->errors = true;
+
+            if (i == max_shown / 2)
+                errorSupplemental(cur->loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown);
+
+            if (i < max_shown / 2 ||
+                i >= n_instantiations - max_shown + max_shown / 2)
+                errorSupplemental(cur->loc, format, cur->toChars());
+            ++i;
+        }
+    }
+}
+
+Dsymbol *TemplateInstance::toAlias()
+{
+#if LOG
+    printf("TemplateInstance::toAlias()\n");
+#endif
+    if (!inst)
+    {
+        // Maybe we can resolve it
+        if (_scope)
+        {
+            semantic(_scope);
+        }
+        if (!inst)
+        {
+            error("cannot resolve forward reference");
+            errors = true;
+            return this;
+        }
+    }
+
+    if (inst != this)
+        return inst->toAlias();
+
+    if (aliasdecl)
+    {
+        return aliasdecl->toAlias();
+    }
+
+    return inst;
+}
+
+const char *TemplateInstance::kind()
+{
+    return "template instance";
+}
+
+bool TemplateInstance::oneMember(Dsymbol **ps, Identifier *ident)
+{
+    *ps = NULL;
+    return true;
+}
+
+const char *TemplateInstance::toChars()
+{
+    OutBuffer buf;
+    toCBufferInstance(this, &buf);
+    return buf.extractString();
+}
+
+const char *TemplateInstance::toPrettyCharsHelper()
+{
+    OutBuffer buf;
+    toCBufferInstance(this, &buf, true);
+    return buf.extractString();
+}
+
+/*************************************
+ * Compare proposed template instantiation with existing template instantiation.
+ * Note that this is not commutative because of the auto ref check.
+ * Params:
+ *  this = proposed template instantiation
+ *  o = existing template instantiation
+ * Returns:
+ *  0 for match, 1 for no match
+ */
+int TemplateInstance::compare(RootObject *o)
+{
+    TemplateInstance *ti = (TemplateInstance *)o;
+
+    //printf("this = %p, ti = %p\n", this, ti);
+    assert(tdtypes.dim == ti->tdtypes.dim);
+
+    // Nesting must match
+    if (enclosing != ti->enclosing)
+    {
+        //printf("test2 enclosing %s ti->enclosing %s\n", enclosing ? enclosing->toChars() : "", ti->enclosing ? ti->enclosing->toChars() : "");
+        goto Lnotequals;
+    }
+    //printf("parent = %s, ti->parent = %s\n", parent->toPrettyChars(), ti->parent->toPrettyChars());
+
+    if (!arrayObjectMatch(&tdtypes, &ti->tdtypes))
+        goto Lnotequals;
+
+    /* Template functions may have different instantiations based on
+     * "auto ref" parameters.
+     */
+    if (FuncDeclaration *fd = ti->toAlias()->isFuncDeclaration())
+    {
+        if (!fd->errors)
+        {
+            Parameters *fparameters = fd->getParameters(NULL);
+            size_t nfparams = Parameter::dim(fparameters);   // Num function parameters
+            for (size_t j = 0; j < nfparams; j++)
+            {
+                Parameter *fparam = Parameter::getNth(fparameters, j);
+                if (fparam->storageClass & STCautoref)       // if "auto ref"
+                {
+                    if (!fargs)
+                        goto Lnotequals;
+                    if (fargs->dim <= j)
+                        break;
+                    Expression *farg = (*fargs)[j];
+                    if (farg->isLvalue())
+                    {
+                        if (!(fparam->storageClass & STCref))
+                            goto Lnotequals;                // auto ref's don't match
+                    }
+                    else
+                    {
+                        if (fparam->storageClass & STCref)
+                            goto Lnotequals;                // auto ref's don't match
+                    }
+                }
+            }
+        }
+    }
+    return 0;
+
+  Lnotequals:
+    return 1;
+}
+
+hash_t TemplateInstance::toHash()
+{
+    if (!hash)
+    {
+        hash = (size_t)(void *)enclosing;
+        hash += arrayObjectHash(&tdtypes);
+        hash += hash == 0;
+    }
+    return hash;
+}
+
+/**************************************
+ * IsExpression can evaluate the specified type speculatively, and even if
+ * it instantiates any symbols, they are normally unnecessary for the
+ * final executable.
+ * However, if those symbols leak to the actual code, compiler should remark
+ * them as non-speculative to generate their code and link to the final executable.
+ */
+void unSpeculative(Scope *sc, RootObject *o)
+{
+    if (!o)
+        return;
+
+    if (Tuple *tup = isTuple(o))
+    {
+        for (size_t i = 0; i < tup->objects.dim; i++)
+        {
+            unSpeculative(sc, tup->objects[i]);
+        }
+        return;
+    }
+
+    Dsymbol *s = getDsymbol(o);
+    if (!s)
+        return;
+
+    if (Declaration *d = s->isDeclaration())
+    {
+        if (VarDeclaration *vd = d->isVarDeclaration())
+            o = vd->type;
+        else if (AliasDeclaration *ad = d->isAliasDeclaration())
+        {
+            o = ad->getType();
+            if (!o)
+                o = ad->toAlias();
+        }
+        else
+            o = d->toAlias();
+
+        s = getDsymbol(o);
+        if (!s)
+            return;
+    }
+
+    if (TemplateInstance *ti = s->isTemplateInstance())
+    {
+        // If the instance is already non-speculative,
+        // or it is leaked to the speculative scope.
+        if (ti->minst != NULL || sc->minst == NULL)
+            return;
+
+        // Remark as non-speculative instance.
+        ti->minst = sc->minst;
+        if (!ti->tinst)
+            ti->tinst = sc->tinst;
+
+        unSpeculative(sc, ti->tempdecl);
+    }
+
+    if (TemplateInstance *ti = s->isInstantiated())
+        unSpeculative(sc, ti);
+}
+
+/***********************************************
+ * Returns true if this is not instantiated in non-root module, and
+ * is a part of non-speculative instantiatiation.
+ *
+ * Note: minst does not stabilize until semantic analysis is completed,
+ * so don't call this function during semantic analysis to return precise result.
+ */
+bool TemplateInstance::needsCodegen()
+{
+    // Now -allInst is just for the backward compatibility.
+    if (global.params.allInst)
+    {
+        //printf("%s minst = %s, enclosing (%s)->isNonRoot = %d\n",
+        //    toPrettyChars(), minst ? minst->toChars() : NULL,
+        //    enclosing ? enclosing->toPrettyChars() : NULL, enclosing && enclosing->inNonRoot());
+        if (enclosing)
+        {
+            // Bugzilla 14588: If the captured context is not a function
+            // (e.g. class), the instance layout determination is guaranteed,
+            // because the semantic/semantic2 pass will be executed
+            // even for non-root instances.
+            if (!enclosing->isFuncDeclaration())
+                return true;
+
+            // Bugzilla 14834: If the captured context is a function,
+            // this excessive instantiation may cause ODR violation, because
+            // -allInst and others doesn't guarantee the semantic3 execution
+            // for that function.
+
+            // If the enclosing is also an instantiated function,
+            // we have to rely on the ancestor's needsCodegen() result.
+            if (TemplateInstance *ti = enclosing->isInstantiated())
+                return ti->needsCodegen();
+
+            // Bugzilla 13415: If and only if the enclosing scope needs codegen,
+            // this nested templates would also need code generation.
+            return !enclosing->inNonRoot();
+        }
+        return true;
+    }
+
+    if (!minst)
+    {
+        // If this is a speculative instantiation,
+        // 1. do codegen if ancestors really needs codegen.
+        // 2. become non-speculative if siblings are not speculative
+
+        TemplateInstance *tnext = this->tnext;
+        TemplateInstance *tinst = this->tinst;
+        // At first, disconnect chain first to prevent infinite recursion.
+        this->tnext = NULL;
+        this->tinst = NULL;
+
+        // Determine necessity of tinst before tnext.
+        if (tinst && tinst->needsCodegen())
+        {
+            minst = tinst->minst;   // cache result
+            assert(minst);
+            assert(minst->isRoot() || minst->rootImports());
+            return true;
+        }
+        if (tnext && (tnext->needsCodegen() || tnext->minst))
+        {
+            minst = tnext->minst;   // cache result
+            assert(minst);
+            return minst->isRoot() || minst->rootImports();
+        }
+
+        // Elide codegen because this is really speculative.
+        return false;
+    }
+
+    /* Even when this is reached to the codegen pass,
+     * a non-root nested template should not generate code,
+     * due to avoid ODR violation.
+     */
+    if (enclosing && enclosing->inNonRoot())
+    {
+        if (tinst)
+        {
+            bool r = tinst->needsCodegen();
+            minst = tinst->minst; // cache result
+            return r;
+        }
+        if (tnext)
+        {
+            bool r = tnext->needsCodegen();
+            minst = tnext->minst; // cache result
+            return r;
+        }
+        return false;
+    }
+
+    /* The issue is that if the importee is compiled with a different -debug
+     * setting than the importer, the importer may believe it exists
+     * in the compiled importee when it does not, when the instantiation
+     * is behind a conditional debug declaration.
+     */
+    // workaround for Bugzilla 11239
+    if (global.params.useUnitTests ||
+        global.params.debuglevel)
+    {
+        // Prefer instantiations from root modules, to maximize link-ability.
+        if (minst->isRoot())
+            return true;
+
+        TemplateInstance *tnext = this->tnext;
+        TemplateInstance *tinst = this->tinst;
+        this->tnext = NULL;
+        this->tinst = NULL;
+
+        if (tinst && tinst->needsCodegen())
+        {
+            minst = tinst->minst;   // cache result
+            assert(minst);
+            assert(minst->isRoot() || minst->rootImports());
+            return true;
+        }
+        if (tnext && tnext->needsCodegen())
+        {
+            minst = tnext->minst;   // cache result
+            assert(minst);
+            assert(minst->isRoot() || minst->rootImports());
+            return true;
+        }
+
+        // Bugzilla 2500 case
+        if (minst->rootImports())
+            return true;
+
+        // Elide codegen because this is not included in root instances.
+        return false;
+    }
+    else
+    {
+        // Prefer instantiations from non-root module, to minimize object code size.
+
+        /* If a TemplateInstance is ever instantiated by non-root modules,
+         * we do not have to generate code for it,
+         * because it will be generated when the non-root module is compiled.
+         *
+         * But, if the non-root 'minst' imports any root modules, it might still need codegen.
+         *
+         * The problem is if A imports B, and B imports A, and both A
+         * and B instantiate the same template, does the compilation of A
+         * or the compilation of B do the actual instantiation?
+         *
+         * See Bugzilla 2500.
+         */
+        if (!minst->isRoot() && !minst->rootImports())
+            return false;
+
+        TemplateInstance *tnext = this->tnext;
+        this->tnext = NULL;
+
+        if (tnext && !tnext->needsCodegen() && tnext->minst)
+        {
+            minst = tnext->minst;   // cache result
+            assert(!minst->isRoot());
+            return false;
+        }
+
+        // Do codegen because this is not included in non-root instances.
+        return true;
+    }
+}
+
+/* ======================== TemplateMixin ================================ */
+
+TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, TypeQualified *tqual, Objects *tiargs)
+        : TemplateInstance(loc, tqual->idents.dim ? (Identifier *)tqual->idents[tqual->idents.dim - 1]
+                                                  : ((TypeIdentifier *)tqual)->ident)
+{
+    //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : "");
+    this->ident = ident;
+    this->tqual = tqual;
+    this->tiargs = tiargs ? tiargs : new Objects();
+}
+
+Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s)
+{
+    TemplateMixin *tm = new TemplateMixin(loc, ident,
+                (TypeQualified *)tqual->syntaxCopy(), tiargs);
+    return TemplateInstance::syntaxCopy(tm);
+}
+
+bool TemplateMixin::findTempDecl(Scope *sc)
+{
+    // Follow qualifications to find the TemplateDeclaration
+    if (!tempdecl)
+    {
+        Expression *e;
+        Type *t;
+        Dsymbol *s;
+        tqual->resolve(loc, sc, &e, &t, &s);
+        if (!s)
+        {
+            error("is not defined");
+            return false;
+        }
+        s = s->toAlias();
+        tempdecl = s->isTemplateDeclaration();
+        OverloadSet *os = s->isOverloadSet();
+
+        /* If an OverloadSet, look for a unique member that is a template declaration
+         */
+        if (os)
+        {
+            Dsymbol *ds = NULL;
+            for (size_t i = 0; i < os->a.dim; i++)
+            {
+                Dsymbol *s2 = os->a[i]->isTemplateDeclaration();
+                if (s2)
+                {
+                    if (ds)
+                    {
+                        tempdecl = os;
+                        break;
+                    }
+                    ds = s2;
+                }
+            }
+        }
+        if (!tempdecl)
+        {
+            error("%s isn't a template", s->toChars());
+            return false;
+        }
+    }
+    assert(tempdecl);
+
+  struct ParamFwdResTm
+  {
+    static int fp(void *param, Dsymbol *s)
+    {
+        TemplateDeclaration *td = s->isTemplateDeclaration();
+        if (!td)
+            return 0;
+
+        TemplateMixin *tm = (TemplateMixin *)param;
+        if (td->semanticRun == PASSinit)
+        {
+            if (td->_scope)
+                td->semantic(td->_scope);
+            else
+            {
+                tm->semanticRun = PASSinit;
+                return 1;
+            }
+        }
+        return 0;
+    }
+  };
+    // Look for forward references
+    OverloadSet *tovers = tempdecl->isOverloadSet();
+    size_t overs_dim = tovers ? tovers->a.dim : 1;
+    for (size_t oi = 0; oi < overs_dim; oi++)
+    {
+        if (overloadApply(tovers ? tovers->a[oi] : tempdecl, (void *)this, &ParamFwdResTm::fp))
+            return false;
+    }
+    return true;
+}
+
+void TemplateMixin::semantic(Scope *sc)
+{
+#if LOG
+    printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this);
+    fflush(stdout);
+#endif
+    if (semanticRun != PASSinit)
+    {
+        // When a class/struct contains mixin members, and is done over
+        // because of forward references, never reach here so semanticRun
+        // has been reset to PASSinit.
+#if LOG
+        printf("\tsemantic done\n");
+#endif
+        return;
+    }
+    semanticRun = PASSsemantic;
+#if LOG
+    printf("\tdo semantic\n");
+#endif
+
+    Scope *scx = NULL;
+    if (_scope)
+    {
+        sc = _scope;
+        scx = _scope;            // save so we don't make redundant copies
+        _scope = NULL;
+    }
+
+    /* Run semantic on each argument, place results in tiargs[],
+     * then find best match template with tiargs
+     */
+    if (!findTempDecl(sc) ||
+        !semanticTiargs(sc) ||
+        !findBestMatch(sc, NULL))
+    {
+        if (semanticRun == PASSinit)    // forward reference had occured
+        {
+            //printf("forward reference - deferring\n");
+            _scope = scx ? scx : sc->copy();
+            _scope->setNoFree();
+            _scope->_module->addDeferredSemantic(this);
+            return;
+        }
+
+        inst = this;
+        errors = true;
+        return;         // error recovery
+    }
+    TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+    assert(tempdecl);
+
+    if (!ident)
+    {
+        /* Assign scope local unique identifier, as same as lambdas.
+         */
+        const char *s = "__mixin";
+
+        DsymbolTable *symtab;
+        if (FuncDeclaration *func = sc->parent->isFuncDeclaration())
+        {
+            symtab = func->localsymtab;
+            if (symtab)
+            {
+                // Inside template constraint, symtab is not set yet.
+                goto L1;
+            }
+        }
+        else
+        {
+            symtab = sc->parent->isScopeDsymbol()->symtab;
+        L1:
+            assert(symtab);
+            int num = (int)dmd_aaLen(symtab->tab) + 1;
+            ident = Identifier::generateId(s, num);
+            symtab->insert(this);
+        }
+    }
+
+    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 (size_t i = 0; i < tiargs->dim; i++)
+        {
+            RootObject *o = (*tiargs)[i];
+            Type *ta = isType(o);
+            Expression *ea = isExpression(o);
+            Dsymbol *sa = isDsymbol(o);
+            RootObject *tmo = (*tm->tiargs)[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, Prot(PROTpublic));
+            break;
+        }
+    }
+
+#if LOG
+    printf("\tcreate scope for template parameters '%s'\n", toChars());
+#endif
+    Scope *scy = sc->push(this);
+    scy->parent = this;
+
+    argsym = new ScopeDsymbol();
+    argsym->parent = scy->parent;
+    Scope *argscope = scy->push(argsym);
+
+    unsigned errorsave = global.errors;
+
+    // Declare each template parameter as an alias for the argument type
+    declareParameters(argscope);
+
+    // Add members to enclosing scope, as well as this scope
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->addMember(argscope, this);
+        //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 = argscope->push(this);
+    //size_t deferred_dim = Module::deferred.dim;
+
+    static int nest;
+    //printf("%d\n", nest);
+    if (++nest > 500)
+    {
+        global.gag = 0;                 // ensure error message gets printed
+        error("recursive expansion");
+        fatal();
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->setScope(sc2);
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->importAll(sc2);
+    }
+
+    for (size_t i = 0; i < members->dim; i++)
+    {
+        Dsymbol *s = (*members)[i];
+        s->semantic(sc2);
+    }
+
+    nest--;
+
+    /* In DeclDefs scope, TemplateMixin does not have to handle deferred symbols.
+     * Because the members would already call Module::addDeferredSemantic() for themselves.
+     * See Struct, Class, Interface, and EnumDeclaration::semantic().
+     */
+    //if (!sc->func && Module::deferred.dim > deferred_dim) {}
+
+    AggregateDeclaration *ad = toParent()->isAggregateDeclaration();
+    if (sc->func && !ad)
+    {
+        semantic2(sc2);
+        semantic3(sc2);
+    }
+
+    // Give additional context info if error occurred during instantiation
+    if (global.errors != errorsave)
+    {
+        error("error instantiating");
+        errors = true;
+    }
+
+    sc2->pop();
+    argscope->pop();
+    scy->pop();
+
+#if LOG
+    printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this);
+#endif
+}
+
+void TemplateMixin::semantic2(Scope *sc)
+{
+    if (semanticRun >= PASSsemantic2)
+        return;
+    semanticRun = PASSsemantic2;
+#if LOG
+    printf("+TemplateMixin::semantic2('%s')\n", toChars());
+#endif
+    if (members)
+    {
+        assert(sc);
+        sc = sc->push(argsym);
+        sc = sc->push(this);
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[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)
+{
+    if (semanticRun >= PASSsemantic3)
+        return;
+    semanticRun = PASSsemantic3;
+#if LOG
+    printf("TemplateMixin::semantic3('%s')\n", toChars());
+#endif
+    if (members)
+    {
+        sc = sc->push(argsym);
+        sc = sc->push(this);
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            s->semantic3(sc);
+        }
+        sc = sc->pop();
+        sc->pop();
+    }
+}
+
+const char *TemplateMixin::kind()
+{
+    return "mixin";
+}
+
+bool TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident)
+{
+    return Dsymbol::oneMember(ps, ident);
+}
+
+int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param)
+{
+    if (_scope) // if fwd reference
+        semantic(NULL); // try to resolve it
+    if (members)
+    {
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            if (s)
+            {
+                if (s->apply(fp, param))
+                    return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+bool TemplateMixin::hasPointers()
+{
+    //printf("TemplateMixin::hasPointers() %s\n", toChars());
+
+    if (members)
+    {
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            //printf(" s = %s %s\n", s->kind(), s->toChars());
+            if (s->hasPointers())
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
+{
+    //printf("TemplateMixin::setFieldOffset() %s\n", toChars());
+    if (_scope)                  // if fwd reference
+        semantic(NULL);         // try to resolve it
+    if (members)
+    {
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            //printf("\t%s\n", s->toChars());
+            s->setFieldOffset(ad, poffset, isunion);
+        }
+    }
+}
+
+const char *TemplateMixin::toChars()
+{
+    OutBuffer buf;
+    toCBufferInstance(this, &buf);
+    return buf.extractString();
+}
diff --git a/gcc/d/dfrontend/dversion.c b/gcc/d/dfrontend/dversion.c
new file mode 100644
index 00000000000..65d65a72096
--- /dev/null
+++ b/gcc/d/dfrontend/dversion.c
@@ -0,0 +1,199 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/version.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root.h"
+
+#include "identifier.h"
+#include "dsymbol.h"
+#include "cond.h"
+#include "version.h"
+#include "module.h"
+
+void checkReserved(Loc loc, const char *ident);
+
+/* ================================================== */
+
+/* DebugSymbol's happen for statements like:
+ *      debug = identifier;
+ *      debug = integer;
+ */
+
+DebugSymbol::DebugSymbol(Loc loc, Identifier *ident)
+    : Dsymbol(ident)
+{
+    this->loc = loc;
+}
+
+DebugSymbol::DebugSymbol(Loc loc, unsigned level)
+    : Dsymbol()
+{
+    this->level = level;
+    this->loc = loc;
+}
+
+const char *DebugSymbol::toChars()
+{
+    if (ident)
+        return ident->toChars();
+    else
+    {
+        OutBuffer buf;
+        buf.printf("%d", level);
+        return buf.extractString();
+    }
+}
+
+Dsymbol *DebugSymbol::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    DebugSymbol *ds = new DebugSymbol(loc, ident);
+    ds->level = level;
+    return ds;
+}
+
+void DebugSymbol::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+    //printf("DebugSymbol::addMember('%s') %s\n", sds->toChars(), toChars());
+    Module *m = sds->isModule();
+
+    // Do not add the member to the symbol table,
+    // just make sure subsequent debug declarations work.
+    if (ident)
+    {
+        if (!m)
+        {
+            error("declaration must be at module level");
+            errors = true;
+        }
+        else
+        {
+            if (findCondition(m->debugidsNot, ident))
+            {
+                error("defined after use");
+                errors = true;
+            }
+            if (!m->debugids)
+                m->debugids = new Strings();
+            m->debugids->push(ident->toChars());
+        }
+    }
+    else
+    {
+        if (!m)
+        {
+            error("level declaration must be at module level");
+            errors = true;
+        }
+        else
+            m->debuglevel = level;
+    }
+}
+
+void DebugSymbol::semantic(Scope *sc)
+{
+    //printf("DebugSymbol::semantic() %s\n", toChars());
+}
+
+const char *DebugSymbol::kind()
+{
+    return "debug";
+}
+
+/* ================================================== */
+
+/* VersionSymbol's happen for statements like:
+ *      version = identifier;
+ *      version = integer;
+ */
+
+VersionSymbol::VersionSymbol(Loc loc, Identifier *ident)
+    : Dsymbol(ident)
+{
+    this->loc = loc;
+}
+
+VersionSymbol::VersionSymbol(Loc loc, unsigned level)
+    : Dsymbol()
+{
+    this->level = level;
+    this->loc = loc;
+}
+
+const char *VersionSymbol::toChars()
+{
+    if (ident)
+        return ident->toChars();
+    else
+    {
+        OutBuffer buf;
+        buf.printf("%d", level);
+        return buf.extractString();
+    }
+}
+
+Dsymbol *VersionSymbol::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    VersionSymbol *ds = new VersionSymbol(loc, ident);
+    ds->level = level;
+    return ds;
+}
+
+void VersionSymbol::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+    //printf("VersionSymbol::addMember('%s') %s\n", sds->toChars(), toChars());
+    Module *m = sds->isModule();
+
+    // Do not add the member to the symbol table,
+    // just make sure subsequent debug declarations work.
+    if (ident)
+    {
+        checkReserved(loc, ident->toChars());
+        if (!m)
+        {
+            error("declaration must be at module level");
+            errors = true;
+        }
+        else
+        {
+            if (findCondition(m->versionidsNot, ident))
+            {
+                error("defined after use");
+                errors = true;
+            }
+            if (!m->versionids)
+                m->versionids = new Strings();
+            m->versionids->push(ident->toChars());
+        }
+    }
+    else
+    {
+        if (!m)
+        {
+            error("level declaration must be at module level");
+            errors = true;
+        }
+        else
+            m->versionlevel = level;
+    }
+}
+
+void VersionSymbol::semantic(Scope *sc)
+{
+}
+
+const char *VersionSymbol::kind()
+{
+    return "version";
+}
diff --git a/gcc/d/dfrontend/entity.c b/gcc/d/dfrontend/entity.c
new file mode 100644
index 00000000000..b3a0eca12b2
--- /dev/null
+++ b/gcc/d/dfrontend/entity.c
@@ -0,0 +1,2393 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/entity.c
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+#include "port.h"
+
+/*********************************************
+ * Convert from named entity to its encoding.
+ * For reference:
+ *      http://www.htmlhelp.com/reference/html40/entities/
+ *      http://www.w3.org/2003/entities/2007/w3centities-f.ent
+ */
+
+struct NameId
+{
+    const char *name;
+    unsigned value;
+};
+
+static NameId namesA[]={
+        {"Aacgr",            0x00386},  // GREEK CAPITAL LETTER ALPHA WITH TONOS
+        {"aacgr",            0x003AC},  // GREEK SMALL LETTER ALPHA WITH TONOS
+        {"Aacute",           0x000C1},  // LATIN CAPITAL LETTER A WITH ACUTE
+        {"aacute",           0x000E1},  // LATIN SMALL LETTER A WITH ACUTE
+        {"Abreve",           0x00102},  // LATIN CAPITAL LETTER A WITH BREVE
+        {"abreve",           0x00103},  // LATIN SMALL LETTER A WITH BREVE
+        {"ac",               0x0223E},  // INVERTED LAZY S
+        {"acd",              0x0223F},  // SINE WAVE
+//      {"acE",              0x0223E;0x00333},  // INVERTED LAZY S with double underline
+        {"Acirc",            0x000C2},  // LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+        {"acirc",            0x000E2},  // LATIN SMALL LETTER A WITH CIRCUMFLEX
+        {"acute",            0x000B4},  // ACUTE ACCENT
+        {"Acy",              0x00410},  // CYRILLIC CAPITAL LETTER A
+        {"acy",              0x00430},  // CYRILLIC SMALL LETTER A
+        {"AElig",            0x000C6},  // LATIN CAPITAL LETTER AE
+        {"aelig",            0x000E6},  // LATIN SMALL LETTER AE
+        {"af",               0x02061},  // FUNCTION APPLICATION
+        {"Afr",              0x1D504},  // MATHEMATICAL FRAKTUR CAPITAL A
+        {"afr",              0x1D51E},  // MATHEMATICAL FRAKTUR SMALL A
+        {"Agr",              0x00391},  // GREEK CAPITAL LETTER ALPHA
+        {"agr",              0x003B1},  // GREEK SMALL LETTER ALPHA
+        {"Agrave",           0x000C0},  // LATIN CAPITAL LETTER A WITH GRAVE
+        {"agrave",           0x000E0},  // LATIN SMALL LETTER A WITH GRAVE
+        {"alefsym",          0x02135},  // ALEF SYMBOL
+        {"aleph",            0x02135},  // ALEF SYMBOL
+        {"Alpha",            0x00391},  // GREEK CAPITAL LETTER ALPHA
+        {"alpha",            0x003B1},  // GREEK SMALL LETTER ALPHA
+        {"Amacr",            0x00100},  // LATIN CAPITAL LETTER A WITH MACRON
+        {"amacr",            0x00101},  // LATIN SMALL LETTER A WITH MACRON
+        {"amalg",            0x02A3F},  // AMALGAMATION OR COPRODUCT
+        {"amp",              0x00026},  // AMPERSAND
+        {"AMP",              0x00026},  // AMPERSAND
+        {"and",              0x02227},  // LOGICAL AND
+        {"And",              0x02A53},  // DOUBLE LOGICAL AND
+        {"andand",           0x02A55},  // TWO INTERSECTING LOGICAL AND
+        {"andd",             0x02A5C},  // LOGICAL AND WITH HORIZONTAL DASH
+        {"andslope",         0x02A58},  // SLOPING LARGE AND
+        {"andv",             0x02A5A},  // LOGICAL AND WITH MIDDLE STEM
+        {"ang",              0x02220},  // ANGLE
+        {"ange",             0x029A4},  // ANGLE WITH UNDERBAR
+        {"angle",            0x02220},  // ANGLE
+        {"angmsd",           0x02221},  // MEASURED ANGLE
+        {"angmsdaa",         0x029A8},  // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT
+        {"angmsdab",         0x029A9},  // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT
+        {"angmsdac",         0x029AA},  // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT
+        {"angmsdad",         0x029AB},  // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT
+        {"angmsdae",         0x029AC},  // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP
+        {"angmsdaf",         0x029AD},  // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP
+        {"angmsdag",         0x029AE},  // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN
+        {"angmsdah",         0x029AF},  // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN
+        {"angrt",            0x0221F},  // RIGHT ANGLE
+        {"angrtvb",          0x022BE},  // RIGHT ANGLE WITH ARC
+        {"angrtvbd",         0x0299D},  // MEASURED RIGHT ANGLE WITH DOT
+        {"angsph",           0x02222},  // SPHERICAL ANGLE
+        {"angst",            0x000C5},  // LATIN CAPITAL LETTER A WITH RING ABOVE
+        {"angzarr",          0x0237C},  // RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW
+        {"Aogon",            0x00104},  // LATIN CAPITAL LETTER A WITH OGONEK
+        {"aogon",            0x00105},  // LATIN SMALL LETTER A WITH OGONEK
+        {"Aopf",             0x1D538},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL A
+        {"aopf",             0x1D552},  // MATHEMATICAL DOUBLE-STRUCK SMALL A
+        {"ap",               0x02248},  // ALMOST EQUAL TO
+        {"apacir",           0x02A6F},  // ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT
+        {"ape",              0x0224A},  // ALMOST EQUAL OR EQUAL TO
+        {"apE",              0x02A70},  // APPROXIMATELY EQUAL OR EQUAL TO
+        {"apid",             0x0224B},  // TRIPLE TILDE
+        {"apos",             0x00027},  // APOSTROPHE
+        {"ApplyFunction",    0x02061},  // FUNCTION APPLICATION
+        {"approx",           0x02248},  // ALMOST EQUAL TO
+        {"approxeq",         0x0224A},  // ALMOST EQUAL OR EQUAL TO
+        {"Aring",            0x000C5},  // LATIN CAPITAL LETTER A WITH RING ABOVE
+        {"aring",            0x000E5},  // LATIN SMALL LETTER A WITH RING ABOVE
+        {"Ascr",             0x1D49C},  // MATHEMATICAL SCRIPT CAPITAL A
+        {"ascr",             0x1D4B6},  // MATHEMATICAL SCRIPT SMALL A
+        {"Assign",           0x02254},  // COLON EQUALS
+        {"ast",              0x0002A},  // ASTERISK
+        {"asymp",            0x02248},  // ALMOST EQUAL TO
+        {"asympeq",          0x0224D},  // EQUIVALENT TO
+        {"Atilde",           0x000C3},  // LATIN CAPITAL LETTER A WITH TILDE
+        {"atilde",           0x000E3},  // LATIN SMALL LETTER A WITH TILDE
+        {"Auml",             0x000C4},  // LATIN CAPITAL LETTER A WITH DIAERESIS
+        {"auml",             0x000E4},  // LATIN SMALL LETTER A WITH DIAERESIS
+        {"awconint",         0x02233},  // ANTICLOCKWISE CONTOUR INTEGRAL
+        {"awint",            0x02A11},  // ANTICLOCKWISE INTEGRATION
+        {NULL,               0}
+};
+
+static NameId namesB[]={
+        {"backcong",         0x0224C},  // ALL EQUAL TO
+        {"backepsilon",      0x003F6},  // GREEK REVERSED LUNATE EPSILON SYMBOL
+        {"backprime",        0x02035},  // REVERSED PRIME
+        {"backsim",          0x0223D},  // REVERSED TILDE
+        {"backsimeq",        0x022CD},  // REVERSED TILDE EQUALS
+        {"Backslash",        0x02216},  // SET MINUS
+//      "b.alpha",          0x1D6C2},  // MATHEMATICAL BOLD SMALL ALPHA
+        {"Barv",             0x02AE7},  // SHORT DOWN TACK WITH OVERBAR
+        {"barvee",           0x022BD},  // NOR
+        {"barwed",           0x02305},  // PROJECTIVE
+        {"Barwed",           0x02306},  // PERSPECTIVE
+        {"barwedge",         0x02305},  // PROJECTIVE
+//      "b.beta",           0x1D6C3},  // MATHEMATICAL BOLD SMALL BETA
+        {"bbrk",             0x023B5},  // BOTTOM SQUARE BRACKET
+        {"bbrktbrk",         0x023B6},  // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET
+//      "b.chi",            0x1D6D8},  // MATHEMATICAL BOLD SMALL CHI
+        {"bcong",            0x0224C},  // ALL EQUAL TO
+        {"Bcy",              0x00411},  // CYRILLIC CAPITAL LETTER BE
+        {"bcy",              0x00431},  // CYRILLIC SMALL LETTER BE
+//      "b.Delta",          0x1D6AB},  // MATHEMATICAL BOLD CAPITAL DELTA
+//      "b.delta",          0x1D6C5},  // MATHEMATICAL BOLD SMALL DELTA
+        {"bdquo",            0x0201E},  // DOUBLE LOW-9 QUOTATION MARK
+        {"becaus",           0x02235},  // BECAUSE
+        {"because",          0x02235},  // BECAUSE
+        {"Because",          0x02235},  // BECAUSE
+        {"bemptyv",          0x029B0},  // REVERSED EMPTY SET
+        {"bepsi",            0x003F6},  // GREEK REVERSED LUNATE EPSILON SYMBOL
+//      "b.epsi",           0x1D6C6},  // MATHEMATICAL BOLD SMALL EPSILON
+//      "b.epsiv",          0x1D6DC},  // MATHEMATICAL BOLD EPSILON SYMBOL
+        {"bernou",           0x0212C},  // SCRIPT CAPITAL B
+        {"Bernoullis",       0x0212C},  // SCRIPT CAPITAL B
+        {"Beta",             0x00392},  // GREEK CAPITAL LETTER BETA
+        {"beta",             0x003B2},  // GREEK SMALL LETTER BETA
+//      "b.eta",            0x1D6C8},  // MATHEMATICAL BOLD SMALL ETA
+        {"beth",             0x02136},  // BET SYMBOL
+        {"between",          0x0226C},  // BETWEEN
+        {"Bfr",              0x1D505},  // MATHEMATICAL FRAKTUR CAPITAL B
+        {"bfr",              0x1D51F},  // MATHEMATICAL FRAKTUR SMALL B
+//      "b.Gamma",          0x1D6AA},  // MATHEMATICAL BOLD CAPITAL GAMMA
+//      "b.gamma",          0x1D6C4},  // MATHEMATICAL BOLD SMALL GAMMA
+//      "b.Gammad",         0x1D7CA},  // MATHEMATICAL BOLD CAPITAL DIGAMMA
+//      "b.gammad",         0x1D7CB},  // MATHEMATICAL BOLD SMALL DIGAMMA
+        {"Bgr",              0x00392},  // GREEK CAPITAL LETTER BETA
+        {"bgr",              0x003B2},  // GREEK SMALL LETTER BETA
+        {"bigcap",           0x022C2},  // N-ARY INTERSECTION
+        {"bigcirc",          0x025EF},  // LARGE CIRCLE
+        {"bigcup",           0x022C3},  // N-ARY UNION
+        {"bigodot",          0x02A00},  // N-ARY CIRCLED DOT OPERATOR
+        {"bigoplus",         0x02A01},  // N-ARY CIRCLED PLUS OPERATOR
+        {"bigotimes",        0x02A02},  // N-ARY CIRCLED TIMES OPERATOR
+        {"bigsqcup",         0x02A06},  // N-ARY SQUARE UNION OPERATOR
+        {"bigstar",          0x02605},  // BLACK STAR
+        {"bigtriangledown",  0x025BD},  // WHITE DOWN-POINTING TRIANGLE
+        {"bigtriangleup",    0x025B3},  // WHITE UP-POINTING TRIANGLE
+        {"biguplus",         0x02A04},  // N-ARY UNION OPERATOR WITH PLUS
+        {"bigvee",           0x022C1},  // N-ARY LOGICAL OR
+        {"bigwedge",         0x022C0},  // N-ARY LOGICAL AND
+//      "b.iota",           0x1D6CA},  // MATHEMATICAL BOLD SMALL IOTA
+//      "b.kappa",          0x1D6CB},  // MATHEMATICAL BOLD SMALL KAPPA
+//      "b.kappav",         0x1D6DE},  // MATHEMATICAL BOLD KAPPA SYMBOL
+        {"bkarow",           0x0290D},  // RIGHTWARDS DOUBLE DASH ARROW
+        {"blacklozenge",     0x029EB},  // BLACK LOZENGE
+        {"blacksquare",      0x025AA},  // BLACK SMALL SQUARE
+        {"blacktriangle",    0x025B4},  // BLACK UP-POINTING SMALL TRIANGLE
+        {"blacktriangledown", 0x025BE},  // BLACK DOWN-POINTING SMALL TRIANGLE
+        {"blacktriangleleft", 0x025C2},  // BLACK LEFT-POINTING SMALL TRIANGLE
+        {"blacktriangleright", 0x025B8},  // BLACK RIGHT-POINTING SMALL TRIANGLE
+//      "b.Lambda",         0x1D6B2},  // MATHEMATICAL BOLD CAPITAL LAMDA
+//      "b.lambda",         0x1D6CC},  // MATHEMATICAL BOLD SMALL LAMDA
+        {"blank",            0x02423},  // OPEN BOX
+        {"blk12",            0x02592},  // MEDIUM SHADE
+        {"blk14",            0x02591},  // LIGHT SHADE
+        {"blk34",            0x02593},  // DARK SHADE
+        {"block",            0x02588},  // FULL BLOCK
+//      "b.mu",             0x1D6CD},  // MATHEMATICAL BOLD SMALL MU
+//      "bne",              0x0003D;0x020E5},  // EQUALS SIGN with reverse slash
+//      "bnequiv",          0x02261;0x020E5},  // IDENTICAL TO with reverse slash
+        {"bnot",             0x02310},  // REVERSED NOT SIGN
+        {"bNot",             0x02AED},  // REVERSED DOUBLE STROKE NOT SIGN
+//      "b.nu",             0x1D6CE},  // MATHEMATICAL BOLD SMALL NU
+//      "b.Omega",          0x1D6C0},  // MATHEMATICAL BOLD CAPITAL OMEGA
+//      "b.omega",          0x1D6DA},  // MATHEMATICAL BOLD SMALL OMEGA
+        {"Bopf",             0x1D539},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+        {"bopf",             0x1D553},  // MATHEMATICAL DOUBLE-STRUCK SMALL B
+        {"bot",              0x022A5},  // UP TACK
+        {"bottom",           0x022A5},  // UP TACK
+        {"bowtie",           0x022C8},  // BOWTIE
+        {"boxbox",           0x029C9},  // TWO JOINED SQUARES
+        {"boxdl",            0x02510},  // BOX DRAWINGS LIGHT DOWN AND LEFT
+        {"boxdL",            0x02555},  // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+        {"boxDl",            0x02556},  // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+        {"boxDL",            0x02557},  // BOX DRAWINGS DOUBLE DOWN AND LEFT
+        {"boxdr",            0x0250C},  // BOX DRAWINGS LIGHT DOWN AND RIGHT
+        {"boxdR",            0x02552},  // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+        {"boxDr",            0x02553},  // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+        {"boxDR",            0x02554},  // BOX DRAWINGS DOUBLE DOWN AND RIGHT
+        {"boxh",             0x02500},  // BOX DRAWINGS LIGHT HORIZONTAL
+        {"boxH",             0x02550},  // BOX DRAWINGS DOUBLE HORIZONTAL
+        {"boxhd",            0x0252C},  // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+        {"boxHd",            0x02564},  // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+        {"boxhD",            0x02565},  // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+        {"boxHD",            0x02566},  // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+        {"boxhu",            0x02534},  // BOX DRAWINGS LIGHT UP AND HORIZONTAL
+        {"boxHu",            0x02567},  // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+        {"boxhU",            0x02568},  // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+        {"boxHU",            0x02569},  // BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+        {"boxminus",         0x0229F},  // SQUARED MINUS
+        {"boxplus",          0x0229E},  // SQUARED PLUS
+        {"boxtimes",         0x022A0},  // SQUARED TIMES
+        {"boxul",            0x02518},  // BOX DRAWINGS LIGHT UP AND LEFT
+        {"boxuL",            0x0255B},  // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+        {"boxUl",            0x0255C},  // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+        {"boxUL",            0x0255D},  // BOX DRAWINGS DOUBLE UP AND LEFT
+        {"boxur",            0x02514},  // BOX DRAWINGS LIGHT UP AND RIGHT
+        {"boxuR",            0x02558},  // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+        {"boxUr",            0x02559},  // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+        {"boxUR",            0x0255A},  // BOX DRAWINGS DOUBLE UP AND RIGHT
+        {"boxv",             0x02502},  // BOX DRAWINGS LIGHT VERTICAL
+        {"boxV",             0x02551},  // BOX DRAWINGS DOUBLE VERTICAL
+        {"boxvh",            0x0253C},  // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+        {"boxvH",            0x0256A},  // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+        {"boxVh",            0x0256B},  // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+        {"boxVH",            0x0256C},  // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+        {"boxvl",            0x02524},  // BOX DRAWINGS LIGHT VERTICAL AND LEFT
+        {"boxvL",            0x02561},  // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+        {"boxVl",            0x02562},  // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+        {"boxVL",            0x02563},  // BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+        {"boxvr",            0x0251C},  // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+        {"boxvR",            0x0255E},  // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+        {"boxVr",            0x0255F},  // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+        {"boxVR",            0x02560},  // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+//      "b.Phi",            0x1D6BD},  // MATHEMATICAL BOLD CAPITAL PHI
+//      "b.phi",            0x1D6D7},  // MATHEMATICAL BOLD SMALL PHI
+//      "b.phiv",           0x1D6DF},  // MATHEMATICAL BOLD PHI SYMBOL
+//      "b.Pi",             0x1D6B7},  // MATHEMATICAL BOLD CAPITAL PI
+//      "b.pi",             0x1D6D1},  // MATHEMATICAL BOLD SMALL PI
+//      "b.piv",            0x1D6E1},  // MATHEMATICAL BOLD PI SYMBOL
+        {"bprime",           0x02035},  // REVERSED PRIME
+//      "b.Psi",            0x1D6BF},  // MATHEMATICAL BOLD CAPITAL PSI
+//      "b.psi",            0x1D6D9},  // MATHEMATICAL BOLD SMALL PSI
+        {"breve",            0x002D8},  // BREVE
+        {"Breve",            0x002D8},  // BREVE
+//      "b.rho",            0x1D6D2},  // MATHEMATICAL BOLD SMALL RHO
+//      "b.rhov",           0x1D6E0},  // MATHEMATICAL BOLD RHO SYMBOL
+        {"brvbar",           0x000A6},  // BROKEN BAR
+        {"Bscr",             0x0212C},  // SCRIPT CAPITAL B
+        {"bscr",             0x1D4B7},  // MATHEMATICAL SCRIPT SMALL B
+        {"bsemi",            0x0204F},  // REVERSED SEMICOLON
+//      "b.Sigma",          0x1D6BA},  // MATHEMATICAL BOLD CAPITAL SIGMA
+//      "b.sigma",          0x1D6D4},  // MATHEMATICAL BOLD SMALL SIGMA
+//      "b.sigmav",         0x1D6D3},  // MATHEMATICAL BOLD SMALL FINAL SIGMA
+        {"bsim",             0x0223D},  // REVERSED TILDE
+        {"bsime",            0x022CD},  // REVERSED TILDE EQUALS
+        {"bsol",             0x0005C},  // REVERSE SOLIDUS
+        {"bsolb",            0x029C5},  // SQUARED FALLING DIAGONAL SLASH
+        {"bsolhsub",         0x027C8},  // REVERSE SOLIDUS PRECEDING SUBSET
+//      "b.tau",            0x1D6D5},  // MATHEMATICAL BOLD SMALL TAU
+//      "b.Theta",          0x1D6AF},  // MATHEMATICAL BOLD CAPITAL THETA
+//      "b.thetas",         0x1D6C9},  // MATHEMATICAL BOLD SMALL THETA
+//      "b.thetav",         0x1D6DD},  // MATHEMATICAL BOLD THETA SYMBOL
+        {"bull",             0x02022},  // BULLET
+        {"bullet",           0x02022},  // BULLET
+        {"bump",             0x0224E},  // GEOMETRICALLY EQUIVALENT TO
+        {"bumpe",            0x0224F},  // DIFFERENCE BETWEEN
+        {"bumpE",            0x02AAE},  // EQUALS SIGN WITH BUMPY ABOVE
+        {"Bumpeq",           0x0224E},  // GEOMETRICALLY EQUIVALENT TO
+        {"bumpeq",           0x0224F},  // DIFFERENCE BETWEEN
+//      "b.Upsi",           0x1D6BC},  // MATHEMATICAL BOLD CAPITAL UPSILON
+//      "b.upsi",           0x1D6D6},  // MATHEMATICAL BOLD SMALL UPSILON
+//      "b.Xi",             0x1D6B5},  // MATHEMATICAL BOLD CAPITAL XI
+//      "b.xi",             0x1D6CF},  // MATHEMATICAL BOLD SMALL XI
+//      "b.zeta",           0x1D6C7},  // MATHEMATICAL BOLD SMALL ZETA
+        {NULL,               0}
+};
+
+static NameId namesC[]={
+        {"Cacute",           0x00106},  // LATIN CAPITAL LETTER C WITH ACUTE
+        {"cacute",           0x00107},  // LATIN SMALL LETTER C WITH ACUTE
+        {"cap",              0x02229},  // INTERSECTION
+        {"Cap",              0x022D2},  // DOUBLE INTERSECTION
+        {"capand",           0x02A44},  // INTERSECTION WITH LOGICAL AND
+        {"capbrcup",         0x02A49},  // INTERSECTION ABOVE BAR ABOVE UNION
+        {"capcap",           0x02A4B},  // INTERSECTION BESIDE AND JOINED WITH INTERSECTION
+        {"capcup",           0x02A47},  // INTERSECTION ABOVE UNION
+        {"capdot",           0x02A40},  // INTERSECTION WITH DOT
+        {"CapitalDifferentialD", 0x02145},  // DOUBLE-STRUCK ITALIC CAPITAL D
+//      "caps",             0x02229;0x0FE00},  // INTERSECTION with serifs
+        {"caret",            0x02041},  // CARET INSERTION POINT
+        {"caron",            0x002C7},  // CARON
+        {"Cayleys",          0x0212D},  // BLACK-LETTER CAPITAL C
+        {"ccaps",            0x02A4D},  // CLOSED INTERSECTION WITH SERIFS
+        {"Ccaron",           0x0010C},  // LATIN CAPITAL LETTER C WITH CARON
+        {"ccaron",           0x0010D},  // LATIN SMALL LETTER C WITH CARON
+        {"Ccedil",           0x000C7},  // LATIN CAPITAL LETTER C WITH CEDILLA
+        {"ccedil",           0x000E7},  // LATIN SMALL LETTER C WITH CEDILLA
+        {"Ccirc",            0x00108},  // LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+        {"ccirc",            0x00109},  // LATIN SMALL LETTER C WITH CIRCUMFLEX
+        {"Cconint",          0x02230},  // VOLUME INTEGRAL
+        {"ccups",            0x02A4C},  // CLOSED UNION WITH SERIFS
+        {"ccupssm",          0x02A50},  // CLOSED UNION WITH SERIFS AND SMASH PRODUCT
+        {"Cdot",             0x0010A},  // LATIN CAPITAL LETTER C WITH DOT ABOVE
+        {"cdot",             0x0010B},  // LATIN SMALL LETTER C WITH DOT ABOVE
+        {"cedil",            0x000B8},  // CEDILLA
+        {"Cedilla",          0x000B8},  // CEDILLA
+        {"cemptyv",          0x029B2},  // EMPTY SET WITH SMALL CIRCLE ABOVE
+        {"cent",             0x000A2},  // CENT SIGN
+        {"centerdot",        0x000B7},  // MIDDLE DOT
+        {"CenterDot",        0x000B7},  // MIDDLE DOT
+        {"Cfr",              0x0212D},  // BLACK-LETTER CAPITAL C
+        {"cfr",              0x1D520},  // MATHEMATICAL FRAKTUR SMALL C
+        {"CHcy",             0x00427},  // CYRILLIC CAPITAL LETTER CHE
+        {"chcy",             0x00447},  // CYRILLIC SMALL LETTER CHE
+        {"check",            0x02713},  // CHECK MARK
+        {"checkmark",        0x02713},  // CHECK MARK
+        {"Chi",              0x003A7},  // GREEK CAPITAL LETTER CHI
+        {"chi",              0x003C7},  // GREEK SMALL LETTER CHI
+        {"cir",              0x025CB},  // WHITE CIRCLE
+        {"circ",             0x002C6},  // MODIFIER LETTER CIRCUMFLEX ACCENT
+        {"circeq",           0x02257},  // RING EQUAL TO
+        {"circlearrowleft",  0x021BA},  // ANTICLOCKWISE OPEN CIRCLE ARROW
+        {"circlearrowright", 0x021BB},  // CLOCKWISE OPEN CIRCLE ARROW
+        {"circledast",       0x0229B},  // CIRCLED ASTERISK OPERATOR
+        {"circledcirc",      0x0229A},  // CIRCLED RING OPERATOR
+        {"circleddash",      0x0229D},  // CIRCLED DASH
+        {"CircleDot",        0x02299},  // CIRCLED DOT OPERATOR
+        {"circledR",         0x000AE},  // REGISTERED SIGN
+        {"circledS",         0x024C8},  // CIRCLED LATIN CAPITAL LETTER S
+        {"CircleMinus",      0x02296},  // CIRCLED MINUS
+        {"CirclePlus",       0x02295},  // CIRCLED PLUS
+        {"CircleTimes",      0x02297},  // CIRCLED TIMES
+        {"cire",             0x02257},  // RING EQUAL TO
+        {"cirE",             0x029C3},  // CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT
+        {"cirfnint",         0x02A10},  // CIRCULATION FUNCTION
+        {"cirmid",           0x02AEF},  // VERTICAL LINE WITH CIRCLE ABOVE
+        {"cirscir",          0x029C2},  // CIRCLE WITH SMALL CIRCLE TO THE RIGHT
+        {"ClockwiseContourIntegral", 0x02232},  // CLOCKWISE CONTOUR INTEGRAL
+        {"CloseCurlyDoubleQuote", 0x0201D},  // RIGHT DOUBLE QUOTATION MARK
+        {"CloseCurlyQuote",  0x02019},  // RIGHT SINGLE QUOTATION MARK
+        {"clubs",            0x02663},  // BLACK CLUB SUIT
+        {"clubsuit",         0x02663},  // BLACK CLUB SUIT
+        {"colon",            0x0003A},  // COLON
+        {"Colon",            0x02237},  // PROPORTION
+        {"colone",           0x02254},  // COLON EQUALS
+        {"Colone",           0x02A74},  // DOUBLE COLON EQUAL
+        {"coloneq",          0x02254},  // COLON EQUALS
+        {"comma",            0x0002C},  // COMMA
+        {"commat",           0x00040},  // COMMERCIAL AT
+        {"comp",             0x02201},  // COMPLEMENT
+        {"compfn",           0x02218},  // RING OPERATOR
+        {"complement",       0x02201},  // COMPLEMENT
+        {"complexes",        0x02102},  // DOUBLE-STRUCK CAPITAL C
+        {"cong",             0x02245},  // APPROXIMATELY EQUAL TO
+        {"congdot",          0x02A6D},  // CONGRUENT WITH DOT ABOVE
+        {"Congruent",        0x02261},  // IDENTICAL TO
+        {"conint",           0x0222E},  // CONTOUR INTEGRAL
+        {"Conint",           0x0222F},  // SURFACE INTEGRAL
+        {"ContourIntegral",  0x0222E},  // CONTOUR INTEGRAL
+        {"Copf",             0x02102},  // DOUBLE-STRUCK CAPITAL C
+        {"copf",             0x1D554},  // MATHEMATICAL DOUBLE-STRUCK SMALL C
+        {"coprod",           0x02210},  // N-ARY COPRODUCT
+        {"Coproduct",        0x02210},  // N-ARY COPRODUCT
+        {"copy",             0x000A9},  // COPYRIGHT SIGN
+        {"COPY",             0x000A9},  // COPYRIGHT SIGN
+        {"copysr",           0x02117},  // SOUND RECORDING COPYRIGHT
+        {"CounterClockwiseContourIntegral", 0x02233},  // ANTICLOCKWISE CONTOUR INTEGRAL
+        {"crarr",            0x021B5},  // DOWNWARDS ARROW WITH CORNER LEFTWARDS
+        {"cross",            0x02717},  // BALLOT X
+        {"Cross",            0x02A2F},  // VECTOR OR CROSS PRODUCT
+        {"Cscr",             0x1D49E},  // MATHEMATICAL SCRIPT CAPITAL C
+        {"cscr",             0x1D4B8},  // MATHEMATICAL SCRIPT SMALL C
+        {"csub",             0x02ACF},  // CLOSED SUBSET
+        {"csube",            0x02AD1},  // CLOSED SUBSET OR EQUAL TO
+        {"csup",             0x02AD0},  // CLOSED SUPERSET
+        {"csupe",            0x02AD2},  // CLOSED SUPERSET OR EQUAL TO
+        {"ctdot",            0x022EF},  // MIDLINE HORIZONTAL ELLIPSIS
+        {"cudarrl",          0x02938},  // RIGHT-SIDE ARC CLOCKWISE ARROW
+        {"cudarrr",          0x02935},  // ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS
+        {"cuepr",            0x022DE},  // EQUAL TO OR PRECEDES
+        {"cuesc",            0x022DF},  // EQUAL TO OR SUCCEEDS
+        {"cularr",           0x021B6},  // ANTICLOCKWISE TOP SEMICIRCLE ARROW
+        {"cularrp",          0x0293D},  // TOP ARC ANTICLOCKWISE ARROW WITH PLUS
+        {"cup",              0x0222A},  // UNION
+        {"Cup",              0x022D3},  // DOUBLE UNION
+        {"cupbrcap",         0x02A48},  // UNION ABOVE BAR ABOVE INTERSECTION
+        {"CupCap",           0x0224D},  // EQUIVALENT TO
+        {"cupcap",           0x02A46},  // UNION ABOVE INTERSECTION
+        {"cupcup",           0x02A4A},  // UNION BESIDE AND JOINED WITH UNION
+        {"cupdot",           0x0228D},  // MULTISET MULTIPLICATION
+        {"cupor",            0x02A45},  // UNION WITH LOGICAL OR
+//      "cups",             0x0222A;0x0FE00},  // UNION with serifs
+        {"curarr",           0x021B7},  // CLOCKWISE TOP SEMICIRCLE ARROW
+        {"curarrm",          0x0293C},  // TOP ARC CLOCKWISE ARROW WITH MINUS
+        {"curlyeqprec",      0x022DE},  // EQUAL TO OR PRECEDES
+        {"curlyeqsucc",      0x022DF},  // EQUAL TO OR SUCCEEDS
+        {"curlyvee",         0x022CE},  // CURLY LOGICAL OR
+        {"curlywedge",       0x022CF},  // CURLY LOGICAL AND
+        {"curren",           0x000A4},  // CURRENCY SIGN
+        {"curvearrowleft",   0x021B6},  // ANTICLOCKWISE TOP SEMICIRCLE ARROW
+        {"curvearrowright",  0x021B7},  // CLOCKWISE TOP SEMICIRCLE ARROW
+        {"cuvee",            0x022CE},  // CURLY LOGICAL OR
+        {"cuwed",            0x022CF},  // CURLY LOGICAL AND
+        {"cwconint",         0x02232},  // CLOCKWISE CONTOUR INTEGRAL
+        {"cwint",            0x02231},  // CLOCKWISE INTEGRAL
+        {"cylcty",           0x0232D},  // CYLINDRICITY
+        {NULL,               0}
+};
+
+static NameId namesD[]={
+        {"dagger",           0x02020},  // DAGGER
+        {"Dagger",           0x02021},  // DOUBLE DAGGER
+        {"daleth",           0x02138},  // DALET SYMBOL
+        {"darr",             0x02193},  // DOWNWARDS ARROW
+        {"Darr",             0x021A1},  // DOWNWARDS TWO HEADED ARROW
+        {"dArr",             0x021D3},  // DOWNWARDS DOUBLE ARROW
+        {"dash",             0x02010},  // HYPHEN
+        {"dashv",            0x022A3},  // LEFT TACK
+        {"Dashv",            0x02AE4},  // VERTICAL BAR DOUBLE LEFT TURNSTILE
+        {"dbkarow",          0x0290F},  // RIGHTWARDS TRIPLE DASH ARROW
+        {"dblac",            0x002DD},  // DOUBLE ACUTE ACCENT
+        {"Dcaron",           0x0010E},  // LATIN CAPITAL LETTER D WITH CARON
+        {"dcaron",           0x0010F},  // LATIN SMALL LETTER D WITH CARON
+        {"Dcy",              0x00414},  // CYRILLIC CAPITAL LETTER DE
+        {"dcy",              0x00434},  // CYRILLIC SMALL LETTER DE
+        {"DD",               0x02145},  // DOUBLE-STRUCK ITALIC CAPITAL D
+        {"dd",               0x02146},  // DOUBLE-STRUCK ITALIC SMALL D
+        {"ddagger",          0x02021},  // DOUBLE DAGGER
+        {"ddarr",            0x021CA},  // DOWNWARDS PAIRED ARROWS
+        {"DDotrahd",         0x02911},  // RIGHTWARDS ARROW WITH DOTTED STEM
+        {"ddotseq",          0x02A77},  // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW
+        {"deg",              0x000B0},  // DEGREE SIGN
+        {"Del",              0x02207},  // NABLA
+        {"Delta",            0x00394},  // GREEK CAPITAL LETTER DELTA
+        {"delta",            0x003B4},  // GREEK SMALL LETTER DELTA
+        {"demptyv",          0x029B1},  // EMPTY SET WITH OVERBAR
+        {"dfisht",           0x0297F},  // DOWN FISH TAIL
+        {"Dfr",              0x1D507},  // MATHEMATICAL FRAKTUR CAPITAL D
+        {"dfr",              0x1D521},  // MATHEMATICAL FRAKTUR SMALL D
+        {"Dgr",              0x00394},  // GREEK CAPITAL LETTER DELTA
+        {"dgr",              0x003B4},  // GREEK SMALL LETTER DELTA
+        {"dHar",             0x02965},  // DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
+        {"dharl",            0x021C3},  // DOWNWARDS HARPOON WITH BARB LEFTWARDS
+        {"dharr",            0x021C2},  // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
+        {"DiacriticalAcute", 0x000B4},  // ACUTE ACCENT
+        {"DiacriticalDot",   0x002D9},  // DOT ABOVE
+        {"DiacriticalDoubleAcute", 0x002DD},  // DOUBLE ACUTE ACCENT
+        {"DiacriticalGrave", 0x00060},  // GRAVE ACCENT
+        {"DiacriticalTilde", 0x002DC},  // SMALL TILDE
+        {"diam",             0x022C4},  // DIAMOND OPERATOR
+        {"diamond",          0x022C4},  // DIAMOND OPERATOR
+        {"Diamond",          0x022C4},  // DIAMOND OPERATOR
+        {"diamondsuit",      0x02666},  // BLACK DIAMOND SUIT
+        {"diams",            0x02666},  // BLACK DIAMOND SUIT
+        {"die",              0x000A8},  // DIAERESIS
+        {"DifferentialD",    0x02146},  // DOUBLE-STRUCK ITALIC SMALL D
+        {"digamma",          0x003DD},  // GREEK SMALL LETTER DIGAMMA
+        {"disin",            0x022F2},  // ELEMENT OF WITH LONG HORIZONTAL STROKE
+        {"div",              0x000F7},  // DIVISION SIGN
+        {"divide",           0x000F7},  // DIVISION SIGN
+        {"divideontimes",    0x022C7},  // DIVISION TIMES
+        {"divonx",           0x022C7},  // DIVISION TIMES
+        {"DJcy",             0x00402},  // CYRILLIC CAPITAL LETTER DJE
+        {"djcy",             0x00452},  // CYRILLIC SMALL LETTER DJE
+        {"dlcorn",           0x0231E},  // BOTTOM LEFT CORNER
+        {"dlcrop",           0x0230D},  // BOTTOM LEFT CROP
+        {"dollar",           0x00024},  // DOLLAR SIGN
+        {"Dopf",             0x1D53B},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL D
+        {"dopf",             0x1D555},  // MATHEMATICAL DOUBLE-STRUCK SMALL D
+        {"Dot",              0x000A8},  // DIAERESIS
+        {"dot",              0x002D9},  // DOT ABOVE
+        {"DotDot",           0x020DC},  // COMBINING FOUR DOTS ABOVE
+        {"doteq",            0x02250},  // APPROACHES THE LIMIT
+        {"doteqdot",         0x02251},  // GEOMETRICALLY EQUAL TO
+        {"DotEqual",         0x02250},  // APPROACHES THE LIMIT
+        {"dotminus",         0x02238},  // DOT MINUS
+        {"dotplus",          0x02214},  // DOT PLUS
+        {"dotsquare",        0x022A1},  // SQUARED DOT OPERATOR
+        {"doublebarwedge",   0x02306},  // PERSPECTIVE
+        {"DoubleContourIntegral", 0x0222F},  // SURFACE INTEGRAL
+        {"DoubleDot",        0x000A8},  // DIAERESIS
+        {"DoubleDownArrow",  0x021D3},  // DOWNWARDS DOUBLE ARROW
+        {"DoubleLeftArrow",  0x021D0},  // LEFTWARDS DOUBLE ARROW
+        {"DoubleLeftRightArrow", 0x021D4},  // LEFT RIGHT DOUBLE ARROW
+        {"DoubleLeftTee",    0x02AE4},  // VERTICAL BAR DOUBLE LEFT TURNSTILE
+        {"DoubleLongLeftArrow", 0x027F8},  // LONG LEFTWARDS DOUBLE ARROW
+        {"DoubleLongLeftRightArrow", 0x027FA},  // LONG LEFT RIGHT DOUBLE ARROW
+        {"DoubleLongRightArrow", 0x027F9},  // LONG RIGHTWARDS DOUBLE ARROW
+        {"DoubleRightArrow", 0x021D2},  // RIGHTWARDS DOUBLE ARROW
+        {"DoubleRightTee",   0x022A8},  // TRUE
+        {"DoubleUpArrow",    0x021D1},  // UPWARDS DOUBLE ARROW
+        {"DoubleUpDownArrow", 0x021D5},  // UP DOWN DOUBLE ARROW
+        {"DoubleVerticalBar", 0x02225},  // PARALLEL TO
+        {"downarrow",        0x02193},  // DOWNWARDS ARROW
+        {"DownArrow",        0x02193},  // DOWNWARDS ARROW
+        {"Downarrow",        0x021D3},  // DOWNWARDS DOUBLE ARROW
+        {"DownArrowBar",     0x02913},  // DOWNWARDS ARROW TO BAR
+        {"DownArrowUpArrow", 0x021F5},  // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW
+        {"DownBreve",        0x00311},  // COMBINING INVERTED BREVE
+        {"downdownarrows",   0x021CA},  // DOWNWARDS PAIRED ARROWS
+        {"downharpoonleft",  0x021C3},  // DOWNWARDS HARPOON WITH BARB LEFTWARDS
+        {"downharpoonright", 0x021C2},  // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
+        {"DownLeftRightVector", 0x02950},  // LEFT BARB DOWN RIGHT BARB DOWN HARPOON
+        {"DownLeftTeeVector", 0x0295E},  // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR
+        {"DownLeftVector",   0x021BD},  // LEFTWARDS HARPOON WITH BARB DOWNWARDS
+        {"DownLeftVectorBar", 0x02956},  // LEFTWARDS HARPOON WITH BARB DOWN TO BAR
+        {"DownRightTeeVector", 0x0295F},  // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR
+        {"DownRightVector",  0x021C1},  // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
+        {"DownRightVectorBar", 0x02957},  // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR
+        {"DownTee",          0x022A4},  // DOWN TACK
+        {"DownTeeArrow",     0x021A7},  // DOWNWARDS ARROW FROM BAR
+        {"drbkarow",         0x02910},  // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW
+        {"drcorn",           0x0231F},  // BOTTOM RIGHT CORNER
+        {"drcrop",           0x0230C},  // BOTTOM RIGHT CROP
+        {"Dscr",             0x1D49F},  // MATHEMATICAL SCRIPT CAPITAL D
+        {"dscr",             0x1D4B9},  // MATHEMATICAL SCRIPT SMALL D
+        {"DScy",             0x00405},  // CYRILLIC CAPITAL LETTER DZE
+        {"dscy",             0x00455},  // CYRILLIC SMALL LETTER DZE
+        {"dsol",             0x029F6},  // SOLIDUS WITH OVERBAR
+        {"Dstrok",           0x00110},  // LATIN CAPITAL LETTER D WITH STROKE
+        {"dstrok",           0x00111},  // LATIN SMALL LETTER D WITH STROKE
+        {"dtdot",            0x022F1},  // DOWN RIGHT DIAGONAL ELLIPSIS
+        {"dtri",             0x025BF},  // WHITE DOWN-POINTING SMALL TRIANGLE
+        {"dtrif",            0x025BE},  // BLACK DOWN-POINTING SMALL TRIANGLE
+        {"duarr",            0x021F5},  // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW
+        {"duhar",            0x0296F},  // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
+        {"dwangle",          0x029A6},  // OBLIQUE ANGLE OPENING UP
+        {"DZcy",             0x0040F},  // CYRILLIC CAPITAL LETTER DZHE
+        {"dzcy",             0x0045F},  // CYRILLIC SMALL LETTER DZHE
+        {"dzigrarr",         0x027FF},  // LONG RIGHTWARDS SQUIGGLE ARROW
+        {NULL,               0}
+};
+
+static NameId namesE[]={
+        {"Eacgr",            0x00388},  // GREEK CAPITAL LETTER EPSILON WITH TONOS
+        {"eacgr",            0x003AD},  // GREEK SMALL LETTER EPSILON WITH TONOS
+        {"Eacute",           0x000C9},  // LATIN CAPITAL LETTER E WITH ACUTE
+        {"eacute",           0x000E9},  // LATIN SMALL LETTER E WITH ACUTE
+        {"easter",           0x02A6E},  // EQUALS WITH ASTERISK
+        {"Ecaron",           0x0011A},  // LATIN CAPITAL LETTER E WITH CARON
+        {"ecaron",           0x0011B},  // LATIN SMALL LETTER E WITH CARON
+        {"ecir",             0x02256},  // RING IN EQUAL TO
+        {"Ecirc",            0x000CA},  // LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+        {"ecirc",            0x000EA},  // LATIN SMALL LETTER E WITH CIRCUMFLEX
+        {"ecolon",           0x02255},  // EQUALS COLON
+        {"Ecy",              0x0042D},  // CYRILLIC CAPITAL LETTER E
+        {"ecy",              0x0044D},  // CYRILLIC SMALL LETTER E
+        {"eDDot",            0x02A77},  // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW
+        {"Edot",             0x00116},  // LATIN CAPITAL LETTER E WITH DOT ABOVE
+        {"edot",             0x00117},  // LATIN SMALL LETTER E WITH DOT ABOVE
+        {"eDot",             0x02251},  // GEOMETRICALLY EQUAL TO
+        {"ee",               0x02147},  // DOUBLE-STRUCK ITALIC SMALL E
+        {"EEacgr",           0x00389},  // GREEK CAPITAL LETTER ETA WITH TONOS
+        {"eeacgr",           0x003AE},  // GREEK SMALL LETTER ETA WITH TONOS
+        {"EEgr",             0x00397},  // GREEK CAPITAL LETTER ETA
+        {"eegr",             0x003B7},  // GREEK SMALL LETTER ETA
+        {"efDot",            0x02252},  // APPROXIMATELY EQUAL TO OR THE IMAGE OF
+        {"Efr",              0x1D508},  // MATHEMATICAL FRAKTUR CAPITAL E
+        {"efr",              0x1D522},  // MATHEMATICAL FRAKTUR SMALL E
+        {"eg",               0x02A9A},  // DOUBLE-LINE EQUAL TO OR GREATER-THAN
+        {"Egr",              0x00395},  // GREEK CAPITAL LETTER EPSILON
+        {"egr",              0x003B5},  // GREEK SMALL LETTER EPSILON
+        {"Egrave",           0x000C8},  // LATIN CAPITAL LETTER E WITH GRAVE
+        {"egrave",           0x000E8},  // LATIN SMALL LETTER E WITH GRAVE
+        {"egs",              0x02A96},  // SLANTED EQUAL TO OR GREATER-THAN
+        {"egsdot",           0x02A98},  // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE
+        {"el",               0x02A99},  // DOUBLE-LINE EQUAL TO OR LESS-THAN
+        {"Element",          0x02208},  // ELEMENT OF
+        {"elinters",         0x023E7},  // ELECTRICAL INTERSECTION
+        {"ell",              0x02113},  // SCRIPT SMALL L
+        {"els",              0x02A95},  // SLANTED EQUAL TO OR LESS-THAN
+        {"elsdot",           0x02A97},  // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE
+        {"Emacr",            0x00112},  // LATIN CAPITAL LETTER E WITH MACRON
+        {"emacr",            0x00113},  // LATIN SMALL LETTER E WITH MACRON
+        {"empty",            0x02205},  // EMPTY SET
+        {"emptyset",         0x02205},  // EMPTY SET
+        {"EmptySmallSquare", 0x025FB},  // WHITE MEDIUM SQUARE
+        {"emptyv",           0x02205},  // EMPTY SET
+        {"EmptyVerySmallSquare", 0x025AB},  // WHITE SMALL SQUARE
+        {"emsp",             0x02003},  // EM SPACE
+        {"emsp13",           0x02004},  // THREE-PER-EM SPACE
+        {"emsp14",           0x02005},  // FOUR-PER-EM SPACE
+        {"ENG",              0x0014A},  // LATIN CAPITAL LETTER ENG
+        {"eng",              0x0014B},  // LATIN SMALL LETTER ENG
+        {"ensp",             0x02002},  // EN SPACE
+        {"Eogon",            0x00118},  // LATIN CAPITAL LETTER E WITH OGONEK
+        {"eogon",            0x00119},  // LATIN SMALL LETTER E WITH OGONEK
+        {"Eopf",             0x1D53C},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL E
+        {"eopf",             0x1D556},  // MATHEMATICAL DOUBLE-STRUCK SMALL E
+        {"epar",             0x022D5},  // EQUAL AND PARALLEL TO
+        {"eparsl",           0x029E3},  // EQUALS SIGN AND SLANTED PARALLEL
+        {"eplus",            0x02A71},  // EQUALS SIGN ABOVE PLUS SIGN
+        {"epsi",             0x003B5},  // GREEK SMALL LETTER EPSILON
+        {"Epsilon",          0x00395},  // GREEK CAPITAL LETTER EPSILON
+        {"epsilon",          0x003B5},  // GREEK SMALL LETTER EPSILON
+        {"epsiv",            0x003F5},  // GREEK LUNATE EPSILON SYMBOL
+        {"eqcirc",           0x02256},  // RING IN EQUAL TO
+        {"eqcolon",          0x02255},  // EQUALS COLON
+        {"eqsim",            0x02242},  // MINUS TILDE
+        {"eqslantgtr",       0x02A96},  // SLANTED EQUAL TO OR GREATER-THAN
+        {"eqslantless",      0x02A95},  // SLANTED EQUAL TO OR LESS-THAN
+        {"Equal",            0x02A75},  // TWO CONSECUTIVE EQUALS SIGNS
+        {"equals",           0x0003D},  // EQUALS SIGN
+        {"EqualTilde",       0x02242},  // MINUS TILDE
+        {"equest",           0x0225F},  // QUESTIONED EQUAL TO
+        {"Equilibrium",      0x021CC},  // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
+        {"equiv",            0x02261},  // IDENTICAL TO
+        {"equivDD",          0x02A78},  // EQUIVALENT WITH FOUR DOTS ABOVE
+        {"eqvparsl",         0x029E5},  // IDENTICAL TO AND SLANTED PARALLEL
+        {"erarr",            0x02971},  // EQUALS SIGN ABOVE RIGHTWARDS ARROW
+        {"erDot",            0x02253},  // IMAGE OF OR APPROXIMATELY EQUAL TO
+        {"escr",             0x0212F},  // SCRIPT SMALL E
+        {"Escr",             0x02130},  // SCRIPT CAPITAL E
+        {"esdot",            0x02250},  // APPROACHES THE LIMIT
+        {"esim",             0x02242},  // MINUS TILDE
+        {"Esim",             0x02A73},  // EQUALS SIGN ABOVE TILDE OPERATOR
+        {"Eta",              0x00397},  // GREEK CAPITAL LETTER ETA
+        {"eta",              0x003B7},  // GREEK SMALL LETTER ETA
+        {"ETH",              0x000D0},  // LATIN CAPITAL LETTER ETH
+        {"eth",              0x000F0},  // LATIN SMALL LETTER ETH
+        {"Euml",             0x000CB},  // LATIN CAPITAL LETTER E WITH DIAERESIS
+        {"euml",             0x000EB},  // LATIN SMALL LETTER E WITH DIAERESIS
+        {"euro",             0x020AC},  // EURO SIGN
+        {"excl",             0x00021},  // EXCLAMATION MARK
+        {"exist",            0x02203},  // THERE EXISTS
+        {"Exists",           0x02203},  // THERE EXISTS
+        {"expectation",      0x02130},  // SCRIPT CAPITAL E
+        {"exponentiale",     0x02147},  // DOUBLE-STRUCK ITALIC SMALL E
+        {"ExponentialE",     0x02147},  // DOUBLE-STRUCK ITALIC SMALL E
+        {NULL,               0}
+};
+
+static NameId namesF[]={
+        {"fallingdotseq",    0x02252},  // APPROXIMATELY EQUAL TO OR THE IMAGE OF
+        {"Fcy",              0x00424},  // CYRILLIC CAPITAL LETTER EF
+        {"fcy",              0x00444},  // CYRILLIC SMALL LETTER EF
+        {"female",           0x02640},  // FEMALE SIGN
+        {"ffilig",           0x0FB03},  // LATIN SMALL LIGATURE FFI
+        {"fflig",            0x0FB00},  // LATIN SMALL LIGATURE FF
+        {"ffllig",           0x0FB04},  // LATIN SMALL LIGATURE FFL
+        {"Ffr",              0x1D509},  // MATHEMATICAL FRAKTUR CAPITAL F
+        {"ffr",              0x1D523},  // MATHEMATICAL FRAKTUR SMALL F
+        {"filig",            0x0FB01},  // LATIN SMALL LIGATURE FI
+        {"FilledSmallSquare", 0x025FC},  // BLACK MEDIUM SQUARE
+        {"FilledVerySmallSquare", 0x025AA},  // BLACK SMALL SQUARE
+//      "fjlig",            0x00066;0x0006A},  // fj ligature
+        {"flat",             0x0266D},  // MUSIC FLAT SIGN
+        {"fllig",            0x0FB02},  // LATIN SMALL LIGATURE FL
+        {"fltns",            0x025B1},  // WHITE PARALLELOGRAM
+        {"fnof",             0x00192},  // LATIN SMALL LETTER F WITH HOOK
+        {"Fopf",             0x1D53D},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL F
+        {"fopf",             0x1D557},  // MATHEMATICAL DOUBLE-STRUCK SMALL F
+        {"forall",           0x02200},  // FOR ALL
+        {"ForAll",           0x02200},  // FOR ALL
+        {"fork",             0x022D4},  // PITCHFORK
+        {"forkv",            0x02AD9},  // ELEMENT OF OPENING DOWNWARDS
+        {"Fouriertrf",       0x02131},  // SCRIPT CAPITAL F
+        {"fpartint",         0x02A0D},  // FINITE PART INTEGRAL
+        {"frac12",           0x000BD},  // VULGAR FRACTION ONE HALF
+        {"frac13",           0x02153},  // VULGAR FRACTION ONE THIRD
+        {"frac14",           0x000BC},  // VULGAR FRACTION ONE QUARTER
+        {"frac15",           0x02155},  // VULGAR FRACTION ONE FIFTH
+        {"frac16",           0x02159},  // VULGAR FRACTION ONE SIXTH
+        {"frac18",           0x0215B},  // VULGAR FRACTION ONE EIGHTH
+        {"frac23",           0x02154},  // VULGAR FRACTION TWO THIRDS
+        {"frac25",           0x02156},  // VULGAR FRACTION TWO FIFTHS
+        {"frac34",           0x000BE},  // VULGAR FRACTION THREE QUARTERS
+        {"frac35",           0x02157},  // VULGAR FRACTION THREE FIFTHS
+        {"frac38",           0x0215C},  // VULGAR FRACTION THREE EIGHTHS
+        {"frac45",           0x02158},  // VULGAR FRACTION FOUR FIFTHS
+        {"frac56",           0x0215A},  // VULGAR FRACTION FIVE SIXTHS
+        {"frac58",           0x0215D},  // VULGAR FRACTION FIVE EIGHTHS
+        {"frac78",           0x0215E},  // VULGAR FRACTION SEVEN EIGHTHS
+        {"frasl",            0x02044},  // FRACTION SLASH
+        {"frown",            0x02322},  // FROWN
+        {"Fscr",             0x02131},  // SCRIPT CAPITAL F
+        {"fscr",             0x1D4BB},  // MATHEMATICAL SCRIPT SMALL F
+        {NULL,               0}
+};
+
+static NameId namesG[]={
+        {"gacute",           0x001F5},  // LATIN SMALL LETTER G WITH ACUTE
+        {"Gamma",            0x00393},  // GREEK CAPITAL LETTER GAMMA
+        {"gamma",            0x003B3},  // GREEK SMALL LETTER GAMMA
+        {"Gammad",           0x003DC},  // GREEK LETTER DIGAMMA
+        {"gammad",           0x003DD},  // GREEK SMALL LETTER DIGAMMA
+        {"gap",              0x02A86},  // GREATER-THAN OR APPROXIMATE
+        {"Gbreve",           0x0011E},  // LATIN CAPITAL LETTER G WITH BREVE
+        {"gbreve",           0x0011F},  // LATIN SMALL LETTER G WITH BREVE
+        {"Gcedil",           0x00122},  // LATIN CAPITAL LETTER G WITH CEDILLA
+        {"Gcirc",            0x0011C},  // LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+        {"gcirc",            0x0011D},  // LATIN SMALL LETTER G WITH CIRCUMFLEX
+        {"Gcy",              0x00413},  // CYRILLIC CAPITAL LETTER GHE
+        {"gcy",              0x00433},  // CYRILLIC SMALL LETTER GHE
+        {"Gdot",             0x00120},  // LATIN CAPITAL LETTER G WITH DOT ABOVE
+        {"gdot",             0x00121},  // LATIN SMALL LETTER G WITH DOT ABOVE
+        {"ge",               0x02265},  // GREATER-THAN OR EQUAL TO
+        {"gE",               0x02267},  // GREATER-THAN OVER EQUAL TO
+        {"gel",              0x022DB},  // GREATER-THAN EQUAL TO OR LESS-THAN
+        {"gEl",              0x02A8C},  // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
+        {"geq",              0x02265},  // GREATER-THAN OR EQUAL TO
+        {"geqq",             0x02267},  // GREATER-THAN OVER EQUAL TO
+        {"geqslant",         0x02A7E},  // GREATER-THAN OR SLANTED EQUAL TO
+        {"ges",              0x02A7E},  // GREATER-THAN OR SLANTED EQUAL TO
+        {"gescc",            0x02AA9},  // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
+        {"gesdot",           0x02A80},  // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
+        {"gesdoto",          0x02A82},  // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
+        {"gesdotol",         0x02A84},  // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT
+//      "gesl",             0x022DB;0x0FE00},  // GREATER-THAN slanted EQUAL TO OR LESS-THAN
+        {"gesles",           0x02A94},  // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL
+        {"Gfr",              0x1D50A},  // MATHEMATICAL FRAKTUR CAPITAL G
+        {"gfr",              0x1D524},  // MATHEMATICAL FRAKTUR SMALL G
+        {"gg",               0x0226B},  // MUCH GREATER-THAN
+        {"Gg",               0x022D9},  // VERY MUCH GREATER-THAN
+        {"ggg",              0x022D9},  // VERY MUCH GREATER-THAN
+        {"Ggr",              0x00393},  // GREEK CAPITAL LETTER GAMMA
+        {"ggr",              0x003B3},  // GREEK SMALL LETTER GAMMA
+        {"gimel",            0x02137},  // GIMEL SYMBOL
+        {"GJcy",             0x00403},  // CYRILLIC CAPITAL LETTER GJE
+        {"gjcy",             0x00453},  // CYRILLIC SMALL LETTER GJE
+        {"gl",               0x02277},  // GREATER-THAN OR LESS-THAN
+        {"gla",              0x02AA5},  // GREATER-THAN BESIDE LESS-THAN
+        {"glE",              0x02A92},  // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL
+        {"glj",              0x02AA4},  // GREATER-THAN OVERLAPPING LESS-THAN
+        {"gnap",             0x02A8A},  // GREATER-THAN AND NOT APPROXIMATE
+        {"gnapprox",         0x02A8A},  // GREATER-THAN AND NOT APPROXIMATE
+        {"gnE",              0x02269},  // GREATER-THAN BUT NOT EQUAL TO
+        {"gne",              0x02A88},  // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO
+        {"gneq",             0x02A88},  // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO
+        {"gneqq",            0x02269},  // GREATER-THAN BUT NOT EQUAL TO
+        {"gnsim",            0x022E7},  // GREATER-THAN BUT NOT EQUIVALENT TO
+        {"Gopf",             0x1D53E},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+        {"gopf",             0x1D558},  // MATHEMATICAL DOUBLE-STRUCK SMALL G
+        {"grave",            0x00060},  // GRAVE ACCENT
+        {"GreaterEqual",     0x02265},  // GREATER-THAN OR EQUAL TO
+        {"GreaterEqualLess", 0x022DB},  // GREATER-THAN EQUAL TO OR LESS-THAN
+        {"GreaterFullEqual", 0x02267},  // GREATER-THAN OVER EQUAL TO
+        {"GreaterGreater",   0x02AA2},  // DOUBLE NESTED GREATER-THAN
+        {"GreaterLess",      0x02277},  // GREATER-THAN OR LESS-THAN
+        {"GreaterSlantEqual", 0x02A7E},  // GREATER-THAN OR SLANTED EQUAL TO
+        {"GreaterTilde",     0x02273},  // GREATER-THAN OR EQUIVALENT TO
+        {"gscr",             0x0210A},  // SCRIPT SMALL G
+        {"Gscr",             0x1D4A2},  // MATHEMATICAL SCRIPT CAPITAL G
+        {"gsim",             0x02273},  // GREATER-THAN OR EQUIVALENT TO
+        {"gsime",            0x02A8E},  // GREATER-THAN ABOVE SIMILAR OR EQUAL
+        {"gsiml",            0x02A90},  // GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN
+        {"gt",               0x0003E},  // GREATER-THAN SIGN
+        {"GT",               0x0003E},  // GREATER-THAN SIGN
+        {"Gt",               0x0226B},  // MUCH GREATER-THAN
+        {"gtcc",             0x02AA7},  // GREATER-THAN CLOSED BY CURVE
+        {"gtcir",            0x02A7A},  // GREATER-THAN WITH CIRCLE INSIDE
+        {"gtdot",            0x022D7},  // GREATER-THAN WITH DOT
+        {"gtlPar",           0x02995},  // DOUBLE LEFT ARC GREATER-THAN BRACKET
+        {"gtquest",          0x02A7C},  // GREATER-THAN WITH QUESTION MARK ABOVE
+        {"gtrapprox",        0x02A86},  // GREATER-THAN OR APPROXIMATE
+        {"gtrarr",           0x02978},  // GREATER-THAN ABOVE RIGHTWARDS ARROW
+        {"gtrdot",           0x022D7},  // GREATER-THAN WITH DOT
+        {"gtreqless",        0x022DB},  // GREATER-THAN EQUAL TO OR LESS-THAN
+        {"gtreqqless",       0x02A8C},  // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
+        {"gtrless",          0x02277},  // GREATER-THAN OR LESS-THAN
+        {"gtrsim",           0x02273},  // GREATER-THAN OR EQUIVALENT TO
+//      "gvertneqq",        0x02269;0x0FE00},  // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke
+//      "gvnE",             0x02269;0x0FE00},  // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke
+        {NULL,               0}
+};
+
+static NameId namesH[]={
+        {"Hacek",            0x002C7},  // CARON
+        {"hairsp",           0x0200A},  // HAIR SPACE
+        {"half",             0x000BD},  // VULGAR FRACTION ONE HALF
+        {"hamilt",           0x0210B},  // SCRIPT CAPITAL H
+        {"HARDcy",           0x0042A},  // CYRILLIC CAPITAL LETTER HARD SIGN
+        {"hardcy",           0x0044A},  // CYRILLIC SMALL LETTER HARD SIGN
+        {"harr",             0x02194},  // LEFT RIGHT ARROW
+        {"hArr",             0x021D4},  // LEFT RIGHT DOUBLE ARROW
+        {"harrcir",          0x02948},  // LEFT RIGHT ARROW THROUGH SMALL CIRCLE
+        {"harrw",            0x021AD},  // LEFT RIGHT WAVE ARROW
+        {"Hat",              0x0005E},  // CIRCUMFLEX ACCENT
+        {"hbar",             0x0210F},  // PLANCK CONSTANT OVER TWO PI
+        {"Hcirc",            0x00124},  // LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+        {"hcirc",            0x00125},  // LATIN SMALL LETTER H WITH CIRCUMFLEX
+        {"hearts",           0x02665},  // BLACK HEART SUIT
+        {"heartsuit",        0x02665},  // BLACK HEART SUIT
+        {"hellip",           0x02026},  // HORIZONTAL ELLIPSIS
+        {"hercon",           0x022B9},  // HERMITIAN CONJUGATE MATRIX
+        {"Hfr",              0x0210C},  // BLACK-LETTER CAPITAL H
+        {"hfr",              0x1D525},  // MATHEMATICAL FRAKTUR SMALL H
+        {"HilbertSpace",     0x0210B},  // SCRIPT CAPITAL H
+        {"hksearow",         0x02925},  // SOUTH EAST ARROW WITH HOOK
+        {"hkswarow",         0x02926},  // SOUTH WEST ARROW WITH HOOK
+        {"hoarr",            0x021FF},  // LEFT RIGHT OPEN-HEADED ARROW
+        {"homtht",           0x0223B},  // HOMOTHETIC
+        {"hookleftarrow",    0x021A9},  // LEFTWARDS ARROW WITH HOOK
+        {"hookrightarrow",   0x021AA},  // RIGHTWARDS ARROW WITH HOOK
+        {"Hopf",             0x0210D},  // DOUBLE-STRUCK CAPITAL H
+        {"hopf",             0x1D559},  // MATHEMATICAL DOUBLE-STRUCK SMALL H
+        {"horbar",           0x02015},  // HORIZONTAL BAR
+        {"HorizontalLine",   0x02500},  // BOX DRAWINGS LIGHT HORIZONTAL
+        {"Hscr",             0x0210B},  // SCRIPT CAPITAL H
+        {"hscr",             0x1D4BD},  // MATHEMATICAL SCRIPT SMALL H
+        {"hslash",           0x0210F},  // PLANCK CONSTANT OVER TWO PI
+        {"Hstrok",           0x00126},  // LATIN CAPITAL LETTER H WITH STROKE
+        {"hstrok",           0x00127},  // LATIN SMALL LETTER H WITH STROKE
+        {"HumpDownHump",     0x0224E},  // GEOMETRICALLY EQUIVALENT TO
+        {"HumpEqual",        0x0224F},  // DIFFERENCE BETWEEN
+        {"hybull",           0x02043},  // HYPHEN BULLET
+        {"hyphen",           0x02010},  // HYPHEN
+        {NULL,               0}
+};
+
+static NameId namesI[]={
+        {"Iacgr",            0x0038A},  // GREEK CAPITAL LETTER IOTA WITH TONOS
+        {"iacgr",            0x003AF},  // GREEK SMALL LETTER IOTA WITH TONOS
+        {"Iacute",           0x000CD},  // LATIN CAPITAL LETTER I WITH ACUTE
+        {"iacute",           0x000ED},  // LATIN SMALL LETTER I WITH ACUTE
+        {"ic",               0x02063},  // INVISIBLE SEPARATOR
+        {"Icirc",            0x000CE},  // LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+        {"icirc",            0x000EE},  // LATIN SMALL LETTER I WITH CIRCUMFLEX
+        {"Icy",              0x00418},  // CYRILLIC CAPITAL LETTER I
+        {"icy",              0x00438},  // CYRILLIC SMALL LETTER I
+        {"idiagr",           0x00390},  // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+        {"Idigr",            0x003AA},  // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+        {"idigr",            0x003CA},  // GREEK SMALL LETTER IOTA WITH DIALYTIKA
+        {"Idot",             0x00130},  // LATIN CAPITAL LETTER I WITH DOT ABOVE
+        {"IEcy",             0x00415},  // CYRILLIC CAPITAL LETTER IE
+        {"iecy",             0x00435},  // CYRILLIC SMALL LETTER IE
+        {"iexcl",            0x000A1},  // INVERTED EXCLAMATION MARK
+        {"iff",              0x021D4},  // LEFT RIGHT DOUBLE ARROW
+        {"Ifr",              0x02111},  // BLACK-LETTER CAPITAL I
+        {"ifr",              0x1D526},  // MATHEMATICAL FRAKTUR SMALL I
+        {"Igr",              0x00399},  // GREEK CAPITAL LETTER IOTA
+        {"igr",              0x003B9},  // GREEK SMALL LETTER IOTA
+        {"Igrave",           0x000CC},  // LATIN CAPITAL LETTER I WITH GRAVE
+        {"igrave",           0x000EC},  // LATIN SMALL LETTER I WITH GRAVE
+        {"ii",               0x02148},  // DOUBLE-STRUCK ITALIC SMALL I
+        {"iiiint",           0x02A0C},  // QUADRUPLE INTEGRAL OPERATOR
+        {"iiint",            0x0222D},  // TRIPLE INTEGRAL
+        {"iinfin",           0x029DC},  // INCOMPLETE INFINITY
+        {"iiota",            0x02129},  // TURNED GREEK SMALL LETTER IOTA
+        {"IJlig",            0x00132},  // LATIN CAPITAL LIGATURE IJ
+        {"ijlig",            0x00133},  // LATIN SMALL LIGATURE IJ
+        {"Im",               0x02111},  // BLACK-LETTER CAPITAL I
+        {"Imacr",            0x0012A},  // LATIN CAPITAL LETTER I WITH MACRON
+        {"imacr",            0x0012B},  // LATIN SMALL LETTER I WITH MACRON
+        {"image",            0x02111},  // BLACK-LETTER CAPITAL I
+        {"ImaginaryI",       0x02148},  // DOUBLE-STRUCK ITALIC SMALL I
+        {"imagline",         0x02110},  // SCRIPT CAPITAL I
+        {"imagpart",         0x02111},  // BLACK-LETTER CAPITAL I
+        {"imath",            0x00131},  // LATIN SMALL LETTER DOTLESS I
+        {"imof",             0x022B7},  // IMAGE OF
+        {"imped",            0x001B5},  // LATIN CAPITAL LETTER Z WITH STROKE
+        {"Implies",          0x021D2},  // RIGHTWARDS DOUBLE ARROW
+        {"in",               0x02208},  // ELEMENT OF
+        {"incare",           0x02105},  // CARE OF
+        {"infin",            0x0221E},  // INFINITY
+        {"infintie",         0x029DD},  // TIE OVER INFINITY
+        {"inodot",           0x00131},  // LATIN SMALL LETTER DOTLESS I
+        {"int",              0x0222B},  // INTEGRAL
+        {"Int",              0x0222C},  // DOUBLE INTEGRAL
+        {"intcal",           0x022BA},  // INTERCALATE
+        {"integers",         0x02124},  // DOUBLE-STRUCK CAPITAL Z
+        {"Integral",         0x0222B},  // INTEGRAL
+        {"intercal",         0x022BA},  // INTERCALATE
+        {"Intersection",     0x022C2},  // N-ARY INTERSECTION
+        {"intlarhk",         0x02A17},  // INTEGRAL WITH LEFTWARDS ARROW WITH HOOK
+        {"intprod",          0x02A3C},  // INTERIOR PRODUCT
+        {"InvisibleComma",   0x02063},  // INVISIBLE SEPARATOR
+        {"InvisibleTimes",   0x02062},  // INVISIBLE TIMES
+        {"IOcy",             0x00401},  // CYRILLIC CAPITAL LETTER IO
+        {"iocy",             0x00451},  // CYRILLIC SMALL LETTER IO
+        {"Iogon",            0x0012E},  // LATIN CAPITAL LETTER I WITH OGONEK
+        {"iogon",            0x0012F},  // LATIN SMALL LETTER I WITH OGONEK
+        {"Iopf",             0x1D540},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL I
+        {"iopf",             0x1D55A},  // MATHEMATICAL DOUBLE-STRUCK SMALL I
+        {"Iota",             0x00399},  // GREEK CAPITAL LETTER IOTA
+        {"iota",             0x003B9},  // GREEK SMALL LETTER IOTA
+        {"iprod",            0x02A3C},  // INTERIOR PRODUCT
+        {"iquest",           0x000BF},  // INVERTED QUESTION MARK
+        {"Iscr",             0x02110},  // SCRIPT CAPITAL I
+        {"iscr",             0x1D4BE},  // MATHEMATICAL SCRIPT SMALL I
+        {"isin",             0x02208},  // ELEMENT OF
+        {"isindot",          0x022F5},  // ELEMENT OF WITH DOT ABOVE
+        {"isinE",            0x022F9},  // ELEMENT OF WITH TWO HORIZONTAL STROKES
+        {"isins",            0x022F4},  // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+        {"isinsv",           0x022F3},  // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+        {"isinv",            0x02208},  // ELEMENT OF
+        {"it",               0x02062},  // INVISIBLE TIMES
+        {"Itilde",           0x00128},  // LATIN CAPITAL LETTER I WITH TILDE
+        {"itilde",           0x00129},  // LATIN SMALL LETTER I WITH TILDE
+        {"Iukcy",            0x00406},  // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+        {"iukcy",            0x00456},  // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+        {"Iuml",             0x000CF},  // LATIN CAPITAL LETTER I WITH DIAERESIS
+        {"iuml",             0x000EF},  // LATIN SMALL LETTER I WITH DIAERESIS
+        {NULL,               0}
+};
+
+static NameId namesJ[]={
+        {"Jcirc",            0x00134},  // LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+        {"jcirc",            0x00135},  // LATIN SMALL LETTER J WITH CIRCUMFLEX
+        {"Jcy",              0x00419},  // CYRILLIC CAPITAL LETTER SHORT I
+        {"jcy",              0x00439},  // CYRILLIC SMALL LETTER SHORT I
+        {"Jfr",              0x1D50D},  // MATHEMATICAL FRAKTUR CAPITAL J
+        {"jfr",              0x1D527},  // MATHEMATICAL FRAKTUR SMALL J
+        {"jmath",            0x00237},  // LATIN SMALL LETTER DOTLESS J
+        {"Jopf",             0x1D541},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL J
+        {"jopf",             0x1D55B},  // MATHEMATICAL DOUBLE-STRUCK SMALL J
+        {"Jscr",             0x1D4A5},  // MATHEMATICAL SCRIPT CAPITAL J
+        {"jscr",             0x1D4BF},  // MATHEMATICAL SCRIPT SMALL J
+        {"Jsercy",           0x00408},  // CYRILLIC CAPITAL LETTER JE
+        {"jsercy",           0x00458},  // CYRILLIC SMALL LETTER JE
+        {"Jukcy",            0x00404},  // CYRILLIC CAPITAL LETTER UKRAINIAN IE
+        {"jukcy",            0x00454},  // CYRILLIC SMALL LETTER UKRAINIAN IE
+        {NULL,               0}
+};
+
+static NameId namesK[]={
+        {"Kappa",            0x0039A},  // GREEK CAPITAL LETTER KAPPA
+        {"kappa",            0x003BA},  // GREEK SMALL LETTER KAPPA
+        {"kappav",           0x003F0},  // GREEK KAPPA SYMBOL
+        {"Kcedil",           0x00136},  // LATIN CAPITAL LETTER K WITH CEDILLA
+        {"kcedil",           0x00137},  // LATIN SMALL LETTER K WITH CEDILLA
+        {"Kcy",              0x0041A},  // CYRILLIC CAPITAL LETTER KA
+        {"kcy",              0x0043A},  // CYRILLIC SMALL LETTER KA
+        {"Kfr",              0x1D50E},  // MATHEMATICAL FRAKTUR CAPITAL K
+        {"kfr",              0x1D528},  // MATHEMATICAL FRAKTUR SMALL K
+        {"Kgr",              0x0039A},  // GREEK CAPITAL LETTER KAPPA
+        {"kgr",              0x003BA},  // GREEK SMALL LETTER KAPPA
+        {"kgreen",           0x00138},  // LATIN SMALL LETTER KRA
+        {"KHcy",             0x00425},  // CYRILLIC CAPITAL LETTER HA
+        {"khcy",             0x00445},  // CYRILLIC SMALL LETTER HA
+        {"KHgr",             0x003A7},  // GREEK CAPITAL LETTER CHI
+        {"khgr",             0x003C7},  // GREEK SMALL LETTER CHI
+        {"KJcy",             0x0040C},  // CYRILLIC CAPITAL LETTER KJE
+        {"kjcy",             0x0045C},  // CYRILLIC SMALL LETTER KJE
+        {"Kopf",             0x1D542},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL K
+        {"kopf",             0x1D55C},  // MATHEMATICAL DOUBLE-STRUCK SMALL K
+        {"Kscr",             0x1D4A6},  // MATHEMATICAL SCRIPT CAPITAL K
+        {"kscr",             0x1D4C0},  // MATHEMATICAL SCRIPT SMALL K
+        {NULL,               0}
+};
+
+static NameId namesL[]={
+        {"lAarr",            0x021DA},  // LEFTWARDS TRIPLE ARROW
+        {"Lacute",           0x00139},  // LATIN CAPITAL LETTER L WITH ACUTE
+        {"lacute",           0x0013A},  // LATIN SMALL LETTER L WITH ACUTE
+        {"laemptyv",         0x029B4},  // EMPTY SET WITH LEFT ARROW ABOVE
+        {"lagran",           0x02112},  // SCRIPT CAPITAL L
+        {"Lambda",           0x0039B},  // GREEK CAPITAL LETTER LAMDA
+        {"lambda",           0x003BB},  // GREEK SMALL LETTER LAMDA
+        {"lang",             0x027E8},  // MATHEMATICAL LEFT ANGLE BRACKET
+        {"Lang",             0x027EA},  // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+        {"langd",            0x02991},  // LEFT ANGLE BRACKET WITH DOT
+        {"langle",           0x027E8},  // MATHEMATICAL LEFT ANGLE BRACKET
+        {"lap",              0x02A85},  // LESS-THAN OR APPROXIMATE
+        {"Laplacetrf",       0x02112},  // SCRIPT CAPITAL L
+        {"laquo",            0x000AB},  // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+        {"larr",             0x02190},  // LEFTWARDS ARROW
+        {"Larr",             0x0219E},  // LEFTWARDS TWO HEADED ARROW
+        {"lArr",             0x021D0},  // LEFTWARDS DOUBLE ARROW
+        {"larrb",            0x021E4},  // LEFTWARDS ARROW TO BAR
+        {"larrbfs",          0x0291F},  // LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND
+        {"larrfs",           0x0291D},  // LEFTWARDS ARROW TO BLACK DIAMOND
+        {"larrhk",           0x021A9},  // LEFTWARDS ARROW WITH HOOK
+        {"larrlp",           0x021AB},  // LEFTWARDS ARROW WITH LOOP
+        {"larrpl",           0x02939},  // LEFT-SIDE ARC ANTICLOCKWISE ARROW
+        {"larrsim",          0x02973},  // LEFTWARDS ARROW ABOVE TILDE OPERATOR
+        {"larrtl",           0x021A2},  // LEFTWARDS ARROW WITH TAIL
+        {"lat",              0x02AAB},  // LARGER THAN
+        {"latail",           0x02919},  // LEFTWARDS ARROW-TAIL
+        {"lAtail",           0x0291B},  // LEFTWARDS DOUBLE ARROW-TAIL
+        {"late",             0x02AAD},  // LARGER THAN OR EQUAL TO
+//      "lates",            0x02AAD;0x0FE00},  // LARGER THAN OR slanted EQUAL
+        {"lbarr",            0x0290C},  // LEFTWARDS DOUBLE DASH ARROW
+        {"lBarr",            0x0290E},  // LEFTWARDS TRIPLE DASH ARROW
+        {"lbbrk",            0x02772},  // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
+        {"lbrace",           0x0007B},  // LEFT CURLY BRACKET
+        {"lbrack",           0x0005B},  // LEFT SQUARE BRACKET
+        {"lbrke",            0x0298B},  // LEFT SQUARE BRACKET WITH UNDERBAR
+        {"lbrksld",          0x0298F},  // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+        {"lbrkslu",          0x0298D},  // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
+        {"Lcaron",           0x0013D},  // LATIN CAPITAL LETTER L WITH CARON
+        {"lcaron",           0x0013E},  // LATIN SMALL LETTER L WITH CARON
+        {"Lcedil",           0x0013B},  // LATIN CAPITAL LETTER L WITH CEDILLA
+        {"lcedil",           0x0013C},  // LATIN SMALL LETTER L WITH CEDILLA
+        {"lceil",            0x02308},  // LEFT CEILING
+        {"lcub",             0x0007B},  // LEFT CURLY BRACKET
+        {"Lcy",              0x0041B},  // CYRILLIC CAPITAL LETTER EL
+        {"lcy",              0x0043B},  // CYRILLIC SMALL LETTER EL
+        {"ldca",             0x02936},  // ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS
+        {"ldquo",            0x0201C},  // LEFT DOUBLE QUOTATION MARK
+        {"ldquor",           0x0201E},  // DOUBLE LOW-9 QUOTATION MARK
+        {"ldrdhar",          0x02967},  // LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN
+        {"ldrushar",         0x0294B},  // LEFT BARB DOWN RIGHT BARB UP HARPOON
+        {"ldsh",             0x021B2},  // DOWNWARDS ARROW WITH TIP LEFTWARDS
+        {"le",               0x02264},  // LESS-THAN OR EQUAL TO
+        {"lE",               0x02266},  // LESS-THAN OVER EQUAL TO
+        {"LeftAngleBracket", 0x027E8},  // MATHEMATICAL LEFT ANGLE BRACKET
+        {"leftarrow",        0x02190},  // LEFTWARDS ARROW
+        {"LeftArrow",        0x02190},  // LEFTWARDS ARROW
+        {"Leftarrow",        0x021D0},  // LEFTWARDS DOUBLE ARROW
+        {"LeftArrowBar",     0x021E4},  // LEFTWARDS ARROW TO BAR
+        {"LeftArrowRightArrow", 0x021C6},  // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
+        {"leftarrowtail",    0x021A2},  // LEFTWARDS ARROW WITH TAIL
+        {"LeftCeiling",      0x02308},  // LEFT CEILING
+        {"LeftDoubleBracket", 0x027E6},  // MATHEMATICAL LEFT WHITE SQUARE BRACKET
+        {"LeftDownTeeVector", 0x02961},  // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR
+        {"LeftDownVector",   0x021C3},  // DOWNWARDS HARPOON WITH BARB LEFTWARDS
+        {"LeftDownVectorBar", 0x02959},  // DOWNWARDS HARPOON WITH BARB LEFT TO BAR
+        {"LeftFloor",        0x0230A},  // LEFT FLOOR
+        {"leftharpoondown",  0x021BD},  // LEFTWARDS HARPOON WITH BARB DOWNWARDS
+        {"leftharpoonup",    0x021BC},  // LEFTWARDS HARPOON WITH BARB UPWARDS
+        {"leftleftarrows",   0x021C7},  // LEFTWARDS PAIRED ARROWS
+        {"leftrightarrow",   0x02194},  // LEFT RIGHT ARROW
+        {"LeftRightArrow",   0x02194},  // LEFT RIGHT ARROW
+        {"Leftrightarrow",   0x021D4},  // LEFT RIGHT DOUBLE ARROW
+        {"leftrightarrows",  0x021C6},  // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
+        {"leftrightharpoons", 0x021CB},  // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
+        {"leftrightsquigarrow", 0x021AD},  // LEFT RIGHT WAVE ARROW
+        {"LeftRightVector",  0x0294E},  // LEFT BARB UP RIGHT BARB UP HARPOON
+        {"LeftTee",          0x022A3},  // LEFT TACK
+        {"LeftTeeArrow",     0x021A4},  // LEFTWARDS ARROW FROM BAR
+        {"LeftTeeVector",    0x0295A},  // LEFTWARDS HARPOON WITH BARB UP FROM BAR
+        {"leftthreetimes",   0x022CB},  // LEFT SEMIDIRECT PRODUCT
+        {"LeftTriangle",     0x022B2},  // NORMAL SUBGROUP OF
+        {"LeftTriangleBar",  0x029CF},  // LEFT TRIANGLE BESIDE VERTICAL BAR
+        {"LeftTriangleEqual", 0x022B4},  // NORMAL SUBGROUP OF OR EQUAL TO
+        {"LeftUpDownVector", 0x02951},  // UP BARB LEFT DOWN BARB LEFT HARPOON
+        {"LeftUpTeeVector",  0x02960},  // UPWARDS HARPOON WITH BARB LEFT FROM BAR
+        {"LeftUpVector",     0x021BF},  // UPWARDS HARPOON WITH BARB LEFTWARDS
+        {"LeftUpVectorBar",  0x02958},  // UPWARDS HARPOON WITH BARB LEFT TO BAR
+        {"LeftVector",       0x021BC},  // LEFTWARDS HARPOON WITH BARB UPWARDS
+        {"LeftVectorBar",    0x02952},  // LEFTWARDS HARPOON WITH BARB UP TO BAR
+        {"leg",              0x022DA},  // LESS-THAN EQUAL TO OR GREATER-THAN
+        {"lEg",              0x02A8B},  // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN
+        {"leq",              0x02264},  // LESS-THAN OR EQUAL TO
+        {"leqq",             0x02266},  // LESS-THAN OVER EQUAL TO
+        {"leqslant",         0x02A7D},  // LESS-THAN OR SLANTED EQUAL TO
+        {"les",              0x02A7D},  // LESS-THAN OR SLANTED EQUAL TO
+        {"lescc",            0x02AA8},  // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
+        {"lesdot",           0x02A7F},  // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
+        {"lesdoto",          0x02A81},  // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
+        {"lesdotor",         0x02A83},  // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT
+//      "lesg",             0x022DA;0x0FE00},  // LESS-THAN slanted EQUAL TO OR GREATER-THAN
+        {"lesges",           0x02A93},  // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL
+        {"lessapprox",       0x02A85},  // LESS-THAN OR APPROXIMATE
+        {"lessdot",          0x022D6},  // LESS-THAN WITH DOT
+        {"lesseqgtr",        0x022DA},  // LESS-THAN EQUAL TO OR GREATER-THAN
+        {"lesseqqgtr",       0x02A8B},  // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN
+        {"LessEqualGreater", 0x022DA},  // LESS-THAN EQUAL TO OR GREATER-THAN
+        {"LessFullEqual",    0x02266},  // LESS-THAN OVER EQUAL TO
+        {"LessGreater",      0x02276},  // LESS-THAN OR GREATER-THAN
+        {"lessgtr",          0x02276},  // LESS-THAN OR GREATER-THAN
+        {"LessLess",         0x02AA1},  // DOUBLE NESTED LESS-THAN
+        {"lesssim",          0x02272},  // LESS-THAN OR EQUIVALENT TO
+        {"LessSlantEqual",   0x02A7D},  // LESS-THAN OR SLANTED EQUAL TO
+        {"LessTilde",        0x02272},  // LESS-THAN OR EQUIVALENT TO
+        {"lfisht",           0x0297C},  // LEFT FISH TAIL
+        {"lfloor",           0x0230A},  // LEFT FLOOR
+        {"Lfr",              0x1D50F},  // MATHEMATICAL FRAKTUR CAPITAL L
+        {"lfr",              0x1D529},  // MATHEMATICAL FRAKTUR SMALL L
+        {"lg",               0x02276},  // LESS-THAN OR GREATER-THAN
+        {"lgE",              0x02A91},  // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL
+        {"Lgr",              0x0039B},  // GREEK CAPITAL LETTER LAMDA
+        {"lgr",              0x003BB},  // GREEK SMALL LETTER LAMDA
+        {"lHar",             0x02962},  // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN
+        {"lhard",            0x021BD},  // LEFTWARDS HARPOON WITH BARB DOWNWARDS
+        {"lharu",            0x021BC},  // LEFTWARDS HARPOON WITH BARB UPWARDS
+        {"lharul",           0x0296A},  // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH
+        {"lhblk",            0x02584},  // LOWER HALF BLOCK
+        {"LJcy",             0x00409},  // CYRILLIC CAPITAL LETTER LJE
+        {"ljcy",             0x00459},  // CYRILLIC SMALL LETTER LJE
+        {"ll",               0x0226A},  // MUCH LESS-THAN
+        {"Ll",               0x022D8},  // VERY MUCH LESS-THAN
+        {"llarr",            0x021C7},  // LEFTWARDS PAIRED ARROWS
+        {"llcorner",         0x0231E},  // BOTTOM LEFT CORNER
+        {"Lleftarrow",       0x021DA},  // LEFTWARDS TRIPLE ARROW
+        {"llhard",           0x0296B},  // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH
+        {"lltri",            0x025FA},  // LOWER LEFT TRIANGLE
+        {"Lmidot",           0x0013F},  // LATIN CAPITAL LETTER L WITH MIDDLE DOT
+        {"lmidot",           0x00140},  // LATIN SMALL LETTER L WITH MIDDLE DOT
+        {"lmoust",           0x023B0},  // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION
+        {"lmoustache",       0x023B0},  // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION
+        {"lnap",             0x02A89},  // LESS-THAN AND NOT APPROXIMATE
+        {"lnapprox",         0x02A89},  // LESS-THAN AND NOT APPROXIMATE
+        {"lnE",              0x02268},  // LESS-THAN BUT NOT EQUAL TO
+        {"lne",              0x02A87},  // LESS-THAN AND SINGLE-LINE NOT EQUAL TO
+        {"lneq",             0x02A87},  // LESS-THAN AND SINGLE-LINE NOT EQUAL TO
+        {"lneqq",            0x02268},  // LESS-THAN BUT NOT EQUAL TO
+        {"lnsim",            0x022E6},  // LESS-THAN BUT NOT EQUIVALENT TO
+        {"loang",            0x027EC},  // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
+        {"loarr",            0x021FD},  // LEFTWARDS OPEN-HEADED ARROW
+        {"lobrk",            0x027E6},  // MATHEMATICAL LEFT WHITE SQUARE BRACKET
+        {"longleftarrow",    0x027F5},  // LONG LEFTWARDS ARROW
+        {"LongLeftArrow",    0x027F5},  // LONG LEFTWARDS ARROW
+        {"Longleftarrow",    0x027F8},  // LONG LEFTWARDS DOUBLE ARROW
+        {"longleftrightarrow", 0x027F7},  // LONG LEFT RIGHT ARROW
+        {"LongLeftRightArrow", 0x027F7},  // LONG LEFT RIGHT ARROW
+        {"Longleftrightarrow", 0x027FA},  // LONG LEFT RIGHT DOUBLE ARROW
+        {"longmapsto",       0x027FC},  // LONG RIGHTWARDS ARROW FROM BAR
+        {"longrightarrow",   0x027F6},  // LONG RIGHTWARDS ARROW
+        {"LongRightArrow",   0x027F6},  // LONG RIGHTWARDS ARROW
+        {"Longrightarrow",   0x027F9},  // LONG RIGHTWARDS DOUBLE ARROW
+        {"looparrowleft",    0x021AB},  // LEFTWARDS ARROW WITH LOOP
+        {"looparrowright",   0x021AC},  // RIGHTWARDS ARROW WITH LOOP
+        {"lopar",            0x02985},  // LEFT WHITE PARENTHESIS
+        {"Lopf",             0x1D543},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL L
+        {"lopf",             0x1D55D},  // MATHEMATICAL DOUBLE-STRUCK SMALL L
+        {"loplus",           0x02A2D},  // PLUS SIGN IN LEFT HALF CIRCLE
+        {"lotimes",          0x02A34},  // MULTIPLICATION SIGN IN LEFT HALF CIRCLE
+        {"lowast",           0x02217},  // ASTERISK OPERATOR
+        {"lowbar",           0x0005F},  // LOW LINE
+        {"LowerLeftArrow",   0x02199},  // SOUTH WEST ARROW
+        {"LowerRightArrow",  0x02198},  // SOUTH EAST ARROW
+        {"loz",              0x025CA},  // LOZENGE
+        {"lozenge",          0x025CA},  // LOZENGE
+        {"lozf",             0x029EB},  // BLACK LOZENGE
+        {"lpar",             0x00028},  // LEFT PARENTHESIS
+        {"lparlt",           0x02993},  // LEFT ARC LESS-THAN BRACKET
+        {"lrarr",            0x021C6},  // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
+        {"lrcorner",         0x0231F},  // BOTTOM RIGHT CORNER
+        {"lrhar",            0x021CB},  // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
+        {"lrhard",           0x0296D},  // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH
+        {"lrm",              0x0200E},  // LEFT-TO-RIGHT MARK
+        {"lrtri",            0x022BF},  // RIGHT TRIANGLE
+        {"lsaquo",           0x02039},  // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+        {"Lscr",             0x02112},  // SCRIPT CAPITAL L
+        {"lscr",             0x1D4C1},  // MATHEMATICAL SCRIPT SMALL L
+        {"lsh",              0x021B0},  // UPWARDS ARROW WITH TIP LEFTWARDS
+        {"Lsh",              0x021B0},  // UPWARDS ARROW WITH TIP LEFTWARDS
+        {"lsim",             0x02272},  // LESS-THAN OR EQUIVALENT TO
+        {"lsime",            0x02A8D},  // LESS-THAN ABOVE SIMILAR OR EQUAL
+        {"lsimg",            0x02A8F},  // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN
+        {"lsqb",             0x0005B},  // LEFT SQUARE BRACKET
+        {"lsquo",            0x02018},  // LEFT SINGLE QUOTATION MARK
+        {"lsquor",           0x0201A},  // SINGLE LOW-9 QUOTATION MARK
+        {"Lstrok",           0x00141},  // LATIN CAPITAL LETTER L WITH STROKE
+        {"lstrok",           0x00142},  // LATIN SMALL LETTER L WITH STROKE
+        {"lt",               0x0003C},  // LESS-THAN SIGN
+        {"LT",               0x0003C},  // LESS-THAN SIGN
+        {"Lt",               0x0226A},  // MUCH LESS-THAN
+        {"ltcc",             0x02AA6},  // LESS-THAN CLOSED BY CURVE
+        {"ltcir",            0x02A79},  // LESS-THAN WITH CIRCLE INSIDE
+        {"ltdot",            0x022D6},  // LESS-THAN WITH DOT
+        {"lthree",           0x022CB},  // LEFT SEMIDIRECT PRODUCT
+        {"ltimes",           0x022C9},  // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT
+        {"ltlarr",           0x02976},  // LESS-THAN ABOVE LEFTWARDS ARROW
+        {"ltquest",          0x02A7B},  // LESS-THAN WITH QUESTION MARK ABOVE
+        {"ltri",             0x025C3},  // WHITE LEFT-POINTING SMALL TRIANGLE
+        {"ltrie",            0x022B4},  // NORMAL SUBGROUP OF OR EQUAL TO
+        {"ltrif",            0x025C2},  // BLACK LEFT-POINTING SMALL TRIANGLE
+        {"ltrPar",           0x02996},  // DOUBLE RIGHT ARC LESS-THAN BRACKET
+        {"lurdshar",         0x0294A},  // LEFT BARB UP RIGHT BARB DOWN HARPOON
+        {"luruhar",          0x02966},  // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP
+//      "lvertneqq",        0x02268;0x0FE00},  // LESS-THAN BUT NOT EQUAL TO - with vertical stroke
+//      "lvnE",             0x02268;0x0FE00},  // LESS-THAN BUT NOT EQUAL TO - with vertical stroke
+        {NULL,               0}
+};
+
+static NameId namesM[]={
+        {"macr",             0x000AF},  // MACRON
+        {"male",             0x02642},  // MALE SIGN
+        {"malt",             0x02720},  // MALTESE CROSS
+        {"maltese",          0x02720},  // MALTESE CROSS
+        {"map",              0x021A6},  // RIGHTWARDS ARROW FROM BAR
+        {"Map",              0x02905},  // RIGHTWARDS TWO-HEADED ARROW FROM BAR
+        {"mapsto",           0x021A6},  // RIGHTWARDS ARROW FROM BAR
+        {"mapstodown",       0x021A7},  // DOWNWARDS ARROW FROM BAR
+        {"mapstoleft",       0x021A4},  // LEFTWARDS ARROW FROM BAR
+        {"mapstoup",         0x021A5},  // UPWARDS ARROW FROM BAR
+        {"marker",           0x025AE},  // BLACK VERTICAL RECTANGLE
+        {"mcomma",           0x02A29},  // MINUS SIGN WITH COMMA ABOVE
+        {"Mcy",              0x0041C},  // CYRILLIC CAPITAL LETTER EM
+        {"mcy",              0x0043C},  // CYRILLIC SMALL LETTER EM
+        {"mdash",            0x02014},  // EM DASH
+        {"mDDot",            0x0223A},  // GEOMETRIC PROPORTION
+        {"measuredangle",    0x02221},  // MEASURED ANGLE
+        {"MediumSpace",      0x0205F},  // MEDIUM MATHEMATICAL SPACE
+        {"Mellintrf",        0x02133},  // SCRIPT CAPITAL M
+        {"Mfr",              0x1D510},  // MATHEMATICAL FRAKTUR CAPITAL M
+        {"mfr",              0x1D52A},  // MATHEMATICAL FRAKTUR SMALL M
+        {"Mgr",              0x0039C},  // GREEK CAPITAL LETTER MU
+        {"mgr",              0x003BC},  // GREEK SMALL LETTER MU
+        {"mho",              0x02127},  // INVERTED OHM SIGN
+        {"micro",            0x000B5},  // MICRO SIGN
+        {"mid",              0x02223},  // DIVIDES
+        {"midast",           0x0002A},  // ASTERISK
+        {"midcir",           0x02AF0},  // VERTICAL LINE WITH CIRCLE BELOW
+        {"middot",           0x000B7},  // MIDDLE DOT
+        {"minus",            0x02212},  // MINUS SIGN
+        {"minusb",           0x0229F},  // SQUARED MINUS
+        {"minusd",           0x02238},  // DOT MINUS
+        {"minusdu",          0x02A2A},  // MINUS SIGN WITH DOT BELOW
+        {"MinusPlus",        0x02213},  // MINUS-OR-PLUS SIGN
+        {"mlcp",             0x02ADB},  // TRANSVERSAL INTERSECTION
+        {"mldr",             0x02026},  // HORIZONTAL ELLIPSIS
+        {"mnplus",           0x02213},  // MINUS-OR-PLUS SIGN
+        {"models",           0x022A7},  // MODELS
+        {"Mopf",             0x1D544},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+        {"mopf",             0x1D55E},  // MATHEMATICAL DOUBLE-STRUCK SMALL M
+        {"mp",               0x02213},  // MINUS-OR-PLUS SIGN
+        {"Mscr",             0x02133},  // SCRIPT CAPITAL M
+        {"mscr",             0x1D4C2},  // MATHEMATICAL SCRIPT SMALL M
+        {"mstpos",           0x0223E},  // INVERTED LAZY S
+        {"Mu",               0x0039C},  // GREEK CAPITAL LETTER MU
+        {"mu",               0x003BC},  // GREEK SMALL LETTER MU
+        {"multimap",         0x022B8},  // MULTIMAP
+        {"mumap",            0x022B8},  // MULTIMAP
+        {NULL,               0}
+};
+
+static NameId namesN[]={
+        {"nabla",            0x02207},  // NABLA
+        {"Nacute",           0x00143},  // LATIN CAPITAL LETTER N WITH ACUTE
+        {"nacute",           0x00144},  // LATIN SMALL LETTER N WITH ACUTE
+//      "nang",             0x02220;0x020D2},  // ANGLE with vertical line
+        {"nap",              0x02249},  // NOT ALMOST EQUAL TO
+//      "napE",             0x02A70;0x00338},  // APPROXIMATELY EQUAL OR EQUAL TO with slash
+//      "napid",            0x0224B;0x00338},  // TRIPLE TILDE with slash
+        {"napos",            0x00149},  // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+        {"napprox",          0x02249},  // NOT ALMOST EQUAL TO
+        {"natur",            0x0266E},  // MUSIC NATURAL SIGN
+        {"natural",          0x0266E},  // MUSIC NATURAL SIGN
+        {"naturals",         0x02115},  // DOUBLE-STRUCK CAPITAL N
+        {"nbsp",             0x000A0},  // NO-BREAK SPACE
+//      "nbump",            0x0224E;0x00338},  // GEOMETRICALLY EQUIVALENT TO with slash
+//      "nbumpe",           0x0224F;0x00338},  // DIFFERENCE BETWEEN with slash
+        {"ncap",             0x02A43},  // INTERSECTION WITH OVERBAR
+        {"Ncaron",           0x00147},  // LATIN CAPITAL LETTER N WITH CARON
+        {"ncaron",           0x00148},  // LATIN SMALL LETTER N WITH CARON
+        {"Ncedil",           0x00145},  // LATIN CAPITAL LETTER N WITH CEDILLA
+        {"ncedil",           0x00146},  // LATIN SMALL LETTER N WITH CEDILLA
+        {"ncong",            0x02247},  // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
+//      "ncongdot",         0x02A6D;0x00338},  // CONGRUENT WITH DOT ABOVE with slash
+        {"ncup",             0x02A42},  // UNION WITH OVERBAR
+        {"Ncy",              0x0041D},  // CYRILLIC CAPITAL LETTER EN
+        {"ncy",              0x0043D},  // CYRILLIC SMALL LETTER EN
+        {"ndash",            0x02013},  // EN DASH
+        {"ne",               0x02260},  // NOT EQUAL TO
+        {"nearhk",           0x02924},  // NORTH EAST ARROW WITH HOOK
+        {"nearr",            0x02197},  // NORTH EAST ARROW
+        {"neArr",            0x021D7},  // NORTH EAST DOUBLE ARROW
+        {"nearrow",          0x02197},  // NORTH EAST ARROW
+//      "nedot",            0x02250;0x00338},  // APPROACHES THE LIMIT with slash
+        {"NegativeMediumSpace", 0x0200B},  // ZERO WIDTH SPACE
+        {"NegativeThickSpace", 0x0200B},  // ZERO WIDTH SPACE
+        {"NegativeThinSpace", 0x0200B},  // ZERO WIDTH SPACE
+        {"NegativeVeryThinSpace", 0x0200B},  // ZERO WIDTH SPACE
+        {"nequiv",           0x02262},  // NOT IDENTICAL TO
+        {"nesear",           0x02928},  // NORTH EAST ARROW AND SOUTH EAST ARROW
+//      "nesim",            0x02242;0x00338},  // MINUS TILDE with slash
+        {"NestedGreaterGreater", 0x0226B},  // MUCH GREATER-THAN
+        {"NestedLessLess",   0x0226A},  // MUCH LESS-THAN
+        {"NewLine",          0x0000A},  // LINE FEED (LF)
+        {"nexist",           0x02204},  // THERE DOES NOT EXIST
+        {"nexists",          0x02204},  // THERE DOES NOT EXIST
+        {"Nfr",              0x1D511},  // MATHEMATICAL FRAKTUR CAPITAL N
+        {"nfr",              0x1D52B},  // MATHEMATICAL FRAKTUR SMALL N
+//      "ngE",              0x02267;0x00338},  // GREATER-THAN OVER EQUAL TO with slash
+        {"nge",              0x02271},  // NEITHER GREATER-THAN NOR EQUAL TO
+        {"ngeq",             0x02271},  // NEITHER GREATER-THAN NOR EQUAL TO
+//      "ngeqq",            0x02267;0x00338},  // GREATER-THAN OVER EQUAL TO with slash
+//      "ngeqslant",        0x02A7E;0x00338},  // GREATER-THAN OR SLANTED EQUAL TO with slash
+//      "nges",             0x02A7E;0x00338},  // GREATER-THAN OR SLANTED EQUAL TO with slash
+//      "nGg",              0x022D9;0x00338},  // VERY MUCH GREATER-THAN with slash
+        {"Ngr",              0x0039D},  // GREEK CAPITAL LETTER NU
+        {"ngr",              0x003BD},  // GREEK SMALL LETTER NU
+        {"ngsim",            0x02275},  // NEITHER GREATER-THAN NOR EQUIVALENT TO
+//      "nGt",              0x0226B;0x020D2},  // MUCH GREATER THAN with vertical line
+        {"ngt",              0x0226F},  // NOT GREATER-THAN
+        {"ngtr",             0x0226F},  // NOT GREATER-THAN
+//      "nGtv",             0x0226B;0x00338},  // MUCH GREATER THAN with slash
+        {"nharr",            0x021AE},  // LEFT RIGHT ARROW WITH STROKE
+        {"nhArr",            0x021CE},  // LEFT RIGHT DOUBLE ARROW WITH STROKE
+        {"nhpar",            0x02AF2},  // PARALLEL WITH HORIZONTAL STROKE
+        {"ni",               0x0220B},  // CONTAINS AS MEMBER
+        {"nis",              0x022FC},  // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+        {"nisd",             0x022FA},  // CONTAINS WITH LONG HORIZONTAL STROKE
+        {"niv",              0x0220B},  // CONTAINS AS MEMBER
+        {"NJcy",             0x0040A},  // CYRILLIC CAPITAL LETTER NJE
+        {"njcy",             0x0045A},  // CYRILLIC SMALL LETTER NJE
+        {"nlarr",            0x0219A},  // LEFTWARDS ARROW WITH STROKE
+        {"nlArr",            0x021CD},  // LEFTWARDS DOUBLE ARROW WITH STROKE
+        {"nldr",             0x02025},  // TWO DOT LEADER
+//      "nlE",              0x02266;0x00338},  // LESS-THAN OVER EQUAL TO with slash
+        {"nle",              0x02270},  // NEITHER LESS-THAN NOR EQUAL TO
+        {"nleftarrow",       0x0219A},  // LEFTWARDS ARROW WITH STROKE
+        {"nLeftarrow",       0x021CD},  // LEFTWARDS DOUBLE ARROW WITH STROKE
+        {"nleftrightarrow",  0x021AE},  // LEFT RIGHT ARROW WITH STROKE
+        {"nLeftrightarrow",  0x021CE},  // LEFT RIGHT DOUBLE ARROW WITH STROKE
+        {"nleq",             0x02270},  // NEITHER LESS-THAN NOR EQUAL TO
+//      "nleqq",            0x02266;0x00338},  // LESS-THAN OVER EQUAL TO with slash
+//      "nleqslant",        0x02A7D;0x00338},  // LESS-THAN OR SLANTED EQUAL TO with slash
+//      "nles",             0x02A7D;0x00338},  // LESS-THAN OR SLANTED EQUAL TO with slash
+        {"nless",            0x0226E},  // NOT LESS-THAN
+//      "nLl",              0x022D8;0x00338},  // VERY MUCH LESS-THAN with slash
+        {"nlsim",            0x02274},  // NEITHER LESS-THAN NOR EQUIVALENT TO
+//      "nLt",              0x0226A;0x020D2},  // MUCH LESS THAN with vertical line
+        {"nlt",              0x0226E},  // NOT LESS-THAN
+        {"nltri",            0x022EA},  // NOT NORMAL SUBGROUP OF
+        {"nltrie",           0x022EC},  // NOT NORMAL SUBGROUP OF OR EQUAL TO
+//      "nLtv",             0x0226A;0x00338},  // MUCH LESS THAN with slash
+        {"nmid",             0x02224},  // DOES NOT DIVIDE
+        {"NoBreak",          0x02060},  // WORD JOINER
+        {"NonBreakingSpace", 0x000A0},  // NO-BREAK SPACE
+        {"Nopf",             0x02115},  // DOUBLE-STRUCK CAPITAL N
+        {"nopf",             0x1D55F},  // MATHEMATICAL DOUBLE-STRUCK SMALL N
+        {"not",              0x000AC},  // NOT SIGN
+        {"Not",              0x02AEC},  // DOUBLE STROKE NOT SIGN
+        {"NotCongruent",     0x02262},  // NOT IDENTICAL TO
+        {"NotCupCap",        0x0226D},  // NOT EQUIVALENT TO
+        {"NotDoubleVerticalBar", 0x02226},  // NOT PARALLEL TO
+        {"NotElement",       0x02209},  // NOT AN ELEMENT OF
+        {"NotEqual",         0x02260},  // NOT EQUAL TO
+//      "NotEqualTilde",    0x02242;0x00338},  // MINUS TILDE with slash
+        {"NotExists",        0x02204},  // THERE DOES NOT EXIST
+        {"NotGreater",       0x0226F},  // NOT GREATER-THAN
+        {"NotGreaterEqual",  0x02271},  // NEITHER GREATER-THAN NOR EQUAL TO
+//      "NotGreaterFullEqual", 0x02267;0x00338},  // GREATER-THAN OVER EQUAL TO with slash
+//      "NotGreaterGreater", 0x0226B;0x00338},  // MUCH GREATER THAN with slash
+        {"NotGreaterLess",   0x02279},  // NEITHER GREATER-THAN NOR LESS-THAN
+//      "NotGreaterSlantEqual", 0x02A7E;0x00338},  // GREATER-THAN OR SLANTED EQUAL TO with slash
+        {"NotGreaterTilde",  0x02275},  // NEITHER GREATER-THAN NOR EQUIVALENT TO
+//      "NotHumpDownHump",  0x0224E;0x00338},  // GEOMETRICALLY EQUIVALENT TO with slash
+//      "NotHumpEqual",     0x0224F;0x00338},  // DIFFERENCE BETWEEN with slash
+        {"notin",            0x02209},  // NOT AN ELEMENT OF
+//      "notindot",         0x022F5;0x00338},  // ELEMENT OF WITH DOT ABOVE with slash
+//      "notinE",           0x022F9;0x00338},  // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash
+        {"notinva",          0x02209},  // NOT AN ELEMENT OF
+        {"notinvb",          0x022F7},  // SMALL ELEMENT OF WITH OVERBAR
+        {"notinvc",          0x022F6},  // ELEMENT OF WITH OVERBAR
+        {"NotLeftTriangle",  0x022EA},  // NOT NORMAL SUBGROUP OF
+//      "NotLeftTriangleBar", 0x029CF;0x00338},  // LEFT TRIANGLE BESIDE VERTICAL BAR with slash
+        {"NotLeftTriangleEqual", 0x022EC},  // NOT NORMAL SUBGROUP OF OR EQUAL TO
+        {"NotLess",          0x0226E},  // NOT LESS-THAN
+        {"NotLessEqual",     0x02270},  // NEITHER LESS-THAN NOR EQUAL TO
+        {"NotLessGreater",   0x02278},  // NEITHER LESS-THAN NOR GREATER-THAN
+//      "NotLessLess",      0x0226A;0x00338},  // MUCH LESS THAN with slash
+//      "NotLessSlantEqual", 0x02A7D;0x00338},  // LESS-THAN OR SLANTED EQUAL TO with slash
+        {"NotLessTilde",     0x02274},  // NEITHER LESS-THAN NOR EQUIVALENT TO
+//      "NotNestedGreaterGreater", 0x02AA2;0x00338},  // DOUBLE NESTED GREATER-THAN with slash
+//      "NotNestedLessLess", 0x02AA1;0x00338},  // DOUBLE NESTED LESS-THAN with slash
+        {"notni",            0x0220C},  // DOES NOT CONTAIN AS MEMBER
+        {"notniva",          0x0220C},  // DOES NOT CONTAIN AS MEMBER
+        {"notnivb",          0x022FE},  // SMALL CONTAINS WITH OVERBAR
+        {"notnivc",          0x022FD},  // CONTAINS WITH OVERBAR
+        {"NotPrecedes",      0x02280},  // DOES NOT PRECEDE
+//      "NotPrecedesEqual", 0x02AAF;0x00338},  // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
+        {"NotPrecedesSlantEqual", 0x022E0},  // DOES NOT PRECEDE OR EQUAL
+        {"NotReverseElement", 0x0220C},  // DOES NOT CONTAIN AS MEMBER
+        {"NotRightTriangle", 0x022EB},  // DOES NOT CONTAIN AS NORMAL SUBGROUP
+//      "NotRightTriangleBar", 0x029D0;0x00338},  // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash
+        {"NotRightTriangleEqual", 0x022ED},  // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
+//      "NotSquareSubset",  0x0228F;0x00338},  // SQUARE IMAGE OF with slash
+        {"NotSquareSubsetEqual", 0x022E2},  // NOT SQUARE IMAGE OF OR EQUAL TO
+//      "NotSquareSuperset", 0x02290;0x00338},  // SQUARE ORIGINAL OF with slash
+        {"NotSquareSupersetEqual", 0x022E3},  // NOT SQUARE ORIGINAL OF OR EQUAL TO
+//      "NotSubset",        0x02282;0x020D2},  // SUBSET OF with vertical line
+        {"NotSubsetEqual",   0x02288},  // NEITHER A SUBSET OF NOR EQUAL TO
+        {"NotSucceeds",      0x02281},  // DOES NOT SUCCEED
+//      "NotSucceedsEqual", 0x02AB0;0x00338},  // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
+        {"NotSucceedsSlantEqual", 0x022E1},  // DOES NOT SUCCEED OR EQUAL
+//      "NotSucceedsTilde", 0x0227F;0x00338},  // SUCCEEDS OR EQUIVALENT TO with slash
+//      "NotSuperset",      0x02283;0x020D2},  // SUPERSET OF with vertical line
+        {"NotSupersetEqual", 0x02289},  // NEITHER A SUPERSET OF NOR EQUAL TO
+        {"NotTilde",         0x02241},  // NOT TILDE
+        {"NotTildeEqual",    0x02244},  // NOT ASYMPTOTICALLY EQUAL TO
+        {"NotTildeFullEqual", 0x02247},  // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
+        {"NotTildeTilde",    0x02249},  // NOT ALMOST EQUAL TO
+        {"NotVerticalBar",   0x02224},  // DOES NOT DIVIDE
+        {"npar",             0x02226},  // NOT PARALLEL TO
+        {"nparallel",        0x02226},  // NOT PARALLEL TO
+//      "nparsl",           0x02AFD;0x020E5},  // DOUBLE SOLIDUS OPERATOR with reverse slash
+//      "npart",            0x02202;0x00338},  // PARTIAL DIFFERENTIAL with slash
+        {"npolint",          0x02A14},  // LINE INTEGRATION NOT INCLUDING THE POLE
+        {"npr",              0x02280},  // DOES NOT PRECEDE
+        {"nprcue",           0x022E0},  // DOES NOT PRECEDE OR EQUAL
+//      "npre",             0x02AAF;0x00338},  // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
+        {"nprec",            0x02280},  // DOES NOT PRECEDE
+//      "npreceq",          0x02AAF;0x00338},  // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
+        {"nrarr",            0x0219B},  // RIGHTWARDS ARROW WITH STROKE
+        {"nrArr",            0x021CF},  // RIGHTWARDS DOUBLE ARROW WITH STROKE
+//      "nrarrc",           0x02933;0x00338},  // WAVE ARROW POINTING DIRECTLY RIGHT with slash
+//      "nrarrw",           0x0219D;0x00338},  // RIGHTWARDS WAVE ARROW with slash
+        {"nrightarrow",      0x0219B},  // RIGHTWARDS ARROW WITH STROKE
+        {"nRightarrow",      0x021CF},  // RIGHTWARDS DOUBLE ARROW WITH STROKE
+        {"nrtri",            0x022EB},  // DOES NOT CONTAIN AS NORMAL SUBGROUP
+        {"nrtrie",           0x022ED},  // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
+        {"nsc",              0x02281},  // DOES NOT SUCCEED
+        {"nsccue",           0x022E1},  // DOES NOT SUCCEED OR EQUAL
+//      "nsce",             0x02AB0;0x00338},  // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
+        {"Nscr",             0x1D4A9},  // MATHEMATICAL SCRIPT CAPITAL N
+        {"nscr",             0x1D4C3},  // MATHEMATICAL SCRIPT SMALL N
+        {"nshortmid",        0x02224},  // DOES NOT DIVIDE
+        {"nshortparallel",   0x02226},  // NOT PARALLEL TO
+        {"nsim",             0x02241},  // NOT TILDE
+        {"nsime",            0x02244},  // NOT ASYMPTOTICALLY EQUAL TO
+        {"nsimeq",           0x02244},  // NOT ASYMPTOTICALLY EQUAL TO
+        {"nsmid",            0x02224},  // DOES NOT DIVIDE
+        {"nspar",            0x02226},  // NOT PARALLEL TO
+        {"nsqsube",          0x022E2},  // NOT SQUARE IMAGE OF OR EQUAL TO
+        {"nsqsupe",          0x022E3},  // NOT SQUARE ORIGINAL OF OR EQUAL TO
+        {"nsub",             0x02284},  // NOT A SUBSET OF
+        {"nsube",            0x02288},  // NEITHER A SUBSET OF NOR EQUAL TO
+//      "nsubE",            0x02AC5;0x00338},  // SUBSET OF ABOVE EQUALS SIGN with slash
+//      "nsubset",          0x02282;0x020D2},  // SUBSET OF with vertical line
+        {"nsubseteq",        0x02288},  // NEITHER A SUBSET OF NOR EQUAL TO
+//      "nsubseteqq",       0x02AC5;0x00338},  // SUBSET OF ABOVE EQUALS SIGN with slash
+        {"nsucc",            0x02281},  // DOES NOT SUCCEED
+//      "nsucceq",          0x02AB0;0x00338},  // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
+        {"nsup",             0x02285},  // NOT A SUPERSET OF
+        {"nsupe",            0x02289},  // NEITHER A SUPERSET OF NOR EQUAL TO
+//      "nsupE",            0x02AC6;0x00338},  // SUPERSET OF ABOVE EQUALS SIGN with slash
+//      "nsupset",          0x02283;0x020D2},  // SUPERSET OF with vertical line
+        {"nsupseteq",        0x02289},  // NEITHER A SUPERSET OF NOR EQUAL TO
+//      "nsupseteqq",       0x02AC6;0x00338},  // SUPERSET OF ABOVE EQUALS SIGN with slash
+        {"ntgl",             0x02279},  // NEITHER GREATER-THAN NOR LESS-THAN
+        {"Ntilde",           0x000D1},  // LATIN CAPITAL LETTER N WITH TILDE
+        {"ntilde",           0x000F1},  // LATIN SMALL LETTER N WITH TILDE
+        {"ntlg",             0x02278},  // NEITHER LESS-THAN NOR GREATER-THAN
+        {"ntriangleleft",    0x022EA},  // NOT NORMAL SUBGROUP OF
+        {"ntrianglelefteq",  0x022EC},  // NOT NORMAL SUBGROUP OF OR EQUAL TO
+        {"ntriangleright",   0x022EB},  // DOES NOT CONTAIN AS NORMAL SUBGROUP
+        {"ntrianglerighteq", 0x022ED},  // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
+        {"Nu",               0x0039D},  // GREEK CAPITAL LETTER NU
+        {"nu",               0x003BD},  // GREEK SMALL LETTER NU
+        {"num",              0x00023},  // NUMBER SIGN
+        {"numero",           0x02116},  // NUMERO SIGN
+        {"numsp",            0x02007},  // FIGURE SPACE
+//      "nvap",             0x0224D;0x020D2},  // EQUIVALENT TO with vertical line
+        {"nvdash",           0x022AC},  // DOES NOT PROVE
+        {"nvDash",           0x022AD},  // NOT TRUE
+        {"nVdash",           0x022AE},  // DOES NOT FORCE
+        {"nVDash",           0x022AF},  // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
+//      "nvge",             0x02265;0x020D2},  // GREATER-THAN OR EQUAL TO with vertical line
+//      "nvgt",             0x0003E;0x020D2},  // GREATER-THAN SIGN with vertical line
+        {"nvHarr",           0x02904},  // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE
+        {"nvinfin",          0x029DE},  // INFINITY NEGATED WITH VERTICAL BAR
+        {"nvlArr",           0x02902},  // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE
+//      "nvle",             0x02264;0x020D2},  // LESS-THAN OR EQUAL TO with vertical line
+//      "nvlt",             0x0003C;0x020D2},  // LESS-THAN SIGN with vertical line
+//      "nvltrie",          0x022B4;0x020D2},  // NORMAL SUBGROUP OF OR EQUAL TO with vertical line
+        {"nvrArr",           0x02903},  // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE
+//      "nvrtrie",          0x022B5;0x020D2},  // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line
+//      "nvsim",            0x0223C;0x020D2},  // TILDE OPERATOR with vertical line
+        {"nwarhk",           0x02923},  // NORTH WEST ARROW WITH HOOK
+        {"nwarr",            0x02196},  // NORTH WEST ARROW
+        {"nwArr",            0x021D6},  // NORTH WEST DOUBLE ARROW
+        {"nwarrow",          0x02196},  // NORTH WEST ARROW
+        {"nwnear",           0x02927},  // NORTH WEST ARROW AND NORTH EAST ARROW
+        {NULL,               0}
+};
+
+static NameId namesO[]={
+        {"Oacgr",            0x0038C},  // GREEK CAPITAL LETTER OMICRON WITH TONOS
+        {"oacgr",            0x003CC},  // GREEK SMALL LETTER OMICRON WITH TONOS
+        {"Oacute",           0x000D3},  // LATIN CAPITAL LETTER O WITH ACUTE
+        {"oacute",           0x000F3},  // LATIN SMALL LETTER O WITH ACUTE
+        {"oast",             0x0229B},  // CIRCLED ASTERISK OPERATOR
+        {"ocir",             0x0229A},  // CIRCLED RING OPERATOR
+        {"Ocirc",            0x000D4},  // LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+        {"ocirc",            0x000F4},  // LATIN SMALL LETTER O WITH CIRCUMFLEX
+        {"Ocy",              0x0041E},  // CYRILLIC CAPITAL LETTER O
+        {"ocy",              0x0043E},  // CYRILLIC SMALL LETTER O
+        {"odash",            0x0229D},  // CIRCLED DASH
+        {"Odblac",           0x00150},  // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+        {"odblac",           0x00151},  // LATIN SMALL LETTER O WITH DOUBLE ACUTE
+        {"odiv",             0x02A38},  // CIRCLED DIVISION SIGN
+        {"odot",             0x02299},  // CIRCLED DOT OPERATOR
+        {"odsold",           0x029BC},  // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN
+        {"OElig",            0x00152},  // LATIN CAPITAL LIGATURE OE
+        {"oelig",            0x00153},  // LATIN SMALL LIGATURE OE
+        {"ofcir",            0x029BF},  // CIRCLED BULLET
+        {"Ofr",              0x1D512},  // MATHEMATICAL FRAKTUR CAPITAL O
+        {"ofr",              0x1D52C},  // MATHEMATICAL FRAKTUR SMALL O
+        {"ogon",             0x002DB},  // OGONEK
+        {"Ogr",              0x0039F},  // GREEK CAPITAL LETTER OMICRON
+        {"ogr",              0x003BF},  // GREEK SMALL LETTER OMICRON
+        {"Ograve",           0x000D2},  // LATIN CAPITAL LETTER O WITH GRAVE
+        {"ograve",           0x000F2},  // LATIN SMALL LETTER O WITH GRAVE
+        {"ogt",              0x029C1},  // CIRCLED GREATER-THAN
+        {"OHacgr",           0x0038F},  // GREEK CAPITAL LETTER OMEGA WITH TONOS
+        {"ohacgr",           0x003CE},  // GREEK SMALL LETTER OMEGA WITH TONOS
+        {"ohbar",            0x029B5},  // CIRCLE WITH HORIZONTAL BAR
+        {"OHgr",             0x003A9},  // GREEK CAPITAL LETTER OMEGA
+        {"ohgr",             0x003C9},  // GREEK SMALL LETTER OMEGA
+        {"ohm",              0x003A9},  // GREEK CAPITAL LETTER OMEGA
+        {"oint",             0x0222E},  // CONTOUR INTEGRAL
+        {"olarr",            0x021BA},  // ANTICLOCKWISE OPEN CIRCLE ARROW
+        {"olcir",            0x029BE},  // CIRCLED WHITE BULLET
+        {"olcross",          0x029BB},  // CIRCLE WITH SUPERIMPOSED X
+        {"oline",            0x0203E},  // OVERLINE
+        {"olt",              0x029C0},  // CIRCLED LESS-THAN
+        {"Omacr",            0x0014C},  // LATIN CAPITAL LETTER O WITH MACRON
+        {"omacr",            0x0014D},  // LATIN SMALL LETTER O WITH MACRON
+        {"Omega",            0x003A9},  // GREEK CAPITAL LETTER OMEGA
+        {"omega",            0x003C9},  // GREEK SMALL LETTER OMEGA
+        {"Omicron",          0x0039F},  // GREEK CAPITAL LETTER OMICRON
+        {"omicron",          0x003BF},  // GREEK SMALL LETTER OMICRON
+        {"omid",             0x029B6},  // CIRCLED VERTICAL BAR
+        {"ominus",           0x02296},  // CIRCLED MINUS
+        {"Oopf",             0x1D546},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+        {"oopf",             0x1D560},  // MATHEMATICAL DOUBLE-STRUCK SMALL O
+        {"opar",             0x029B7},  // CIRCLED PARALLEL
+        {"OpenCurlyDoubleQuote", 0x0201C},  // LEFT DOUBLE QUOTATION MARK
+        {"OpenCurlyQuote",   0x02018},  // LEFT SINGLE QUOTATION MARK
+        {"operp",            0x029B9},  // CIRCLED PERPENDICULAR
+        {"oplus",            0x02295},  // CIRCLED PLUS
+        {"or",               0x02228},  // LOGICAL OR
+        {"Or",               0x02A54},  // DOUBLE LOGICAL OR
+        {"orarr",            0x021BB},  // CLOCKWISE OPEN CIRCLE ARROW
+        {"ord",              0x02A5D},  // LOGICAL OR WITH HORIZONTAL DASH
+        {"order",            0x02134},  // SCRIPT SMALL O
+        {"orderof",          0x02134},  // SCRIPT SMALL O
+        {"ordf",             0x000AA},  // FEMININE ORDINAL INDICATOR
+        {"ordm",             0x000BA},  // MASCULINE ORDINAL INDICATOR
+        {"origof",           0x022B6},  // ORIGINAL OF
+        {"oror",             0x02A56},  // TWO INTERSECTING LOGICAL OR
+        {"orslope",          0x02A57},  // SLOPING LARGE OR
+        {"orv",              0x02A5B},  // LOGICAL OR WITH MIDDLE STEM
+        {"oS",               0x024C8},  // CIRCLED LATIN CAPITAL LETTER S
+        {"oscr",             0x02134},  // SCRIPT SMALL O
+        {"Oscr",             0x1D4AA},  // MATHEMATICAL SCRIPT CAPITAL O
+        {"Oslash",           0x000D8},  // LATIN CAPITAL LETTER O WITH STROKE
+        {"oslash",           0x000F8},  // LATIN SMALL LETTER O WITH STROKE
+        {"osol",             0x02298},  // CIRCLED DIVISION SLASH
+        {"Otilde",           0x000D5},  // LATIN CAPITAL LETTER O WITH TILDE
+        {"otilde",           0x000F5},  // LATIN SMALL LETTER O WITH TILDE
+        {"otimes",           0x02297},  // CIRCLED TIMES
+        {"Otimes",           0x02A37},  // MULTIPLICATION SIGN IN DOUBLE CIRCLE
+        {"otimesas",         0x02A36},  // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT
+        {"Ouml",             0x000D6},  // LATIN CAPITAL LETTER O WITH DIAERESIS
+        {"ouml",             0x000F6},  // LATIN SMALL LETTER O WITH DIAERESIS
+        {"ovbar",            0x0233D},  // APL FUNCTIONAL SYMBOL CIRCLE STILE
+        {"OverBar",          0x0203E},  // OVERLINE
+        {"OverBrace",        0x023DE},  // TOP CURLY BRACKET
+        {"OverBracket",      0x023B4},  // TOP SQUARE BRACKET
+        {"OverParenthesis",  0x023DC},  // TOP PARENTHESIS
+        {NULL,               0}
+};
+
+static NameId namesP[]={
+        {"par",              0x02225},  // PARALLEL TO
+        {"para",             0x000B6},  // PILCROW SIGN
+        {"parallel",         0x02225},  // PARALLEL TO
+        {"parsim",           0x02AF3},  // PARALLEL WITH TILDE OPERATOR
+        {"parsl",            0x02AFD},  // DOUBLE SOLIDUS OPERATOR
+        {"part",             0x02202},  // PARTIAL DIFFERENTIAL
+        {"PartialD",         0x02202},  // PARTIAL DIFFERENTIAL
+        {"Pcy",              0x0041F},  // CYRILLIC CAPITAL LETTER PE
+        {"pcy",              0x0043F},  // CYRILLIC SMALL LETTER PE
+        {"percnt",           0x00025},  // PERCENT SIGN
+        {"period",           0x0002E},  // FULL STOP
+        {"permil",           0x02030},  // PER MILLE SIGN
+        {"perp",             0x022A5},  // UP TACK
+        {"pertenk",          0x02031},  // PER TEN THOUSAND SIGN
+        {"Pfr",              0x1D513},  // MATHEMATICAL FRAKTUR CAPITAL P
+        {"pfr",              0x1D52D},  // MATHEMATICAL FRAKTUR SMALL P
+        {"Pgr",              0x003A0},  // GREEK CAPITAL LETTER PI
+        {"pgr",              0x003C0},  // GREEK SMALL LETTER PI
+        {"PHgr",             0x003A6},  // GREEK CAPITAL LETTER PHI
+        {"phgr",             0x003C6},  // GREEK SMALL LETTER PHI
+        {"Phi",              0x003A6},  // GREEK CAPITAL LETTER PHI
+        {"phi",              0x003C6},  // GREEK SMALL LETTER PHI
+        {"phiv",             0x003D5},  // GREEK PHI SYMBOL
+        {"phmmat",           0x02133},  // SCRIPT CAPITAL M
+        {"phone",            0x0260E},  // BLACK TELEPHONE
+        {"Pi",               0x003A0},  // GREEK CAPITAL LETTER PI
+        {"pi",               0x003C0},  // GREEK SMALL LETTER PI
+        {"pitchfork",        0x022D4},  // PITCHFORK
+        {"piv",              0x003D6},  // GREEK PI SYMBOL
+        {"planck",           0x0210F},  // PLANCK CONSTANT OVER TWO PI
+        {"planckh",          0x0210E},  // PLANCK CONSTANT
+        {"plankv",           0x0210F},  // PLANCK CONSTANT OVER TWO PI
+        {"plus",             0x0002B},  // PLUS SIGN
+        {"plusacir",         0x02A23},  // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE
+        {"plusb",            0x0229E},  // SQUARED PLUS
+        {"pluscir",          0x02A22},  // PLUS SIGN WITH SMALL CIRCLE ABOVE
+        {"plusdo",           0x02214},  // DOT PLUS
+        {"plusdu",           0x02A25},  // PLUS SIGN WITH DOT BELOW
+        {"pluse",            0x02A72},  // PLUS SIGN ABOVE EQUALS SIGN
+        {"PlusMinus",        0x000B1},  // PLUS-MINUS SIGN
+        {"plusmn",           0x000B1},  // PLUS-MINUS SIGN
+        {"plussim",          0x02A26},  // PLUS SIGN WITH TILDE BELOW
+        {"plustwo",          0x02A27},  // PLUS SIGN WITH SUBSCRIPT TWO
+        {"pm",               0x000B1},  // PLUS-MINUS SIGN
+        {"Poincareplane",    0x0210C},  // BLACK-LETTER CAPITAL H
+        {"pointint",         0x02A15},  // INTEGRAL AROUND A POINT OPERATOR
+        {"Popf",             0x02119},  // DOUBLE-STRUCK CAPITAL P
+        {"popf",             0x1D561},  // MATHEMATICAL DOUBLE-STRUCK SMALL P
+        {"pound",            0x000A3},  // POUND SIGN
+        {"pr",               0x0227A},  // PRECEDES
+        {"Pr",               0x02ABB},  // DOUBLE PRECEDES
+        {"prap",             0x02AB7},  // PRECEDES ABOVE ALMOST EQUAL TO
+        {"prcue",            0x0227C},  // PRECEDES OR EQUAL TO
+        {"pre",              0x02AAF},  // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
+        {"prE",              0x02AB3},  // PRECEDES ABOVE EQUALS SIGN
+        {"prec",             0x0227A},  // PRECEDES
+        {"precapprox",       0x02AB7},  // PRECEDES ABOVE ALMOST EQUAL TO
+        {"preccurlyeq",      0x0227C},  // PRECEDES OR EQUAL TO
+        {"Precedes",         0x0227A},  // PRECEDES
+        {"PrecedesEqual",    0x02AAF},  // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
+        {"PrecedesSlantEqual", 0x0227C},  // PRECEDES OR EQUAL TO
+        {"PrecedesTilde",    0x0227E},  // PRECEDES OR EQUIVALENT TO
+        {"preceq",           0x02AAF},  // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
+        {"precnapprox",      0x02AB9},  // PRECEDES ABOVE NOT ALMOST EQUAL TO
+        {"precneqq",         0x02AB5},  // PRECEDES ABOVE NOT EQUAL TO
+        {"precnsim",         0x022E8},  // PRECEDES BUT NOT EQUIVALENT TO
+        {"precsim",          0x0227E},  // PRECEDES OR EQUIVALENT TO
+        {"prime",            0x02032},  // PRIME
+        {"Prime",            0x02033},  // DOUBLE PRIME
+        {"primes",           0x02119},  // DOUBLE-STRUCK CAPITAL P
+        {"prnap",            0x02AB9},  // PRECEDES ABOVE NOT ALMOST EQUAL TO
+        {"prnE",             0x02AB5},  // PRECEDES ABOVE NOT EQUAL TO
+        {"prnsim",           0x022E8},  // PRECEDES BUT NOT EQUIVALENT TO
+        {"prod",             0x0220F},  // N-ARY PRODUCT
+        {"Product",          0x0220F},  // N-ARY PRODUCT
+        {"profalar",         0x0232E},  // ALL AROUND-PROFILE
+        {"profline",         0x02312},  // ARC
+        {"profsurf",         0x02313},  // SEGMENT
+        {"prop",             0x0221D},  // PROPORTIONAL TO
+        {"Proportion",       0x02237},  // PROPORTION
+        {"Proportional",     0x0221D},  // PROPORTIONAL TO
+        {"propto",           0x0221D},  // PROPORTIONAL TO
+        {"prsim",            0x0227E},  // PRECEDES OR EQUIVALENT TO
+        {"prurel",           0x022B0},  // PRECEDES UNDER RELATION
+        {"Pscr",             0x1D4AB},  // MATHEMATICAL SCRIPT CAPITAL P
+        {"pscr",             0x1D4C5},  // MATHEMATICAL SCRIPT SMALL P
+        {"PSgr",             0x003A8},  // GREEK CAPITAL LETTER PSI
+        {"psgr",             0x003C8},  // GREEK SMALL LETTER PSI
+        {"Psi",              0x003A8},  // GREEK CAPITAL LETTER PSI
+        {"psi",              0x003C8},  // GREEK SMALL LETTER PSI
+        {"puncsp",           0x02008},  // PUNCTUATION SPACE
+        {NULL,               0}
+};
+
+static NameId namesQ[]={
+        {"Qfr",              0x1D514},  // MATHEMATICAL FRAKTUR CAPITAL Q
+        {"qfr",              0x1D52E},  // MATHEMATICAL FRAKTUR SMALL Q
+        {"qint",             0x02A0C},  // QUADRUPLE INTEGRAL OPERATOR
+        {"Qopf",             0x0211A},  // DOUBLE-STRUCK CAPITAL Q
+        {"qopf",             0x1D562},  // MATHEMATICAL DOUBLE-STRUCK SMALL Q
+        {"qprime",           0x02057},  // QUADRUPLE PRIME
+        {"Qscr",             0x1D4AC},  // MATHEMATICAL SCRIPT CAPITAL Q
+        {"qscr",             0x1D4C6},  // MATHEMATICAL SCRIPT SMALL Q
+        {"quaternions",      0x0210D},  // DOUBLE-STRUCK CAPITAL H
+        {"quatint",          0x02A16},  // QUATERNION INTEGRAL OPERATOR
+        {"quest",            0x0003F},  // QUESTION MARK
+        {"questeq",          0x0225F},  // QUESTIONED EQUAL TO
+        {"quot",             0x00022},  // QUOTATION MARK
+        {"QUOT",             0x00022},  // QUOTATION MARK
+        {NULL,               0}
+};
+
+static NameId namesR[]={
+        {"rAarr",            0x021DB},  // RIGHTWARDS TRIPLE ARROW
+//      "race",             0x0223D;0x00331},  // REVERSED TILDE with underline
+        {"Racute",           0x00154},  // LATIN CAPITAL LETTER R WITH ACUTE
+        {"racute",           0x00155},  // LATIN SMALL LETTER R WITH ACUTE
+        {"radic",            0x0221A},  // SQUARE ROOT
+        {"raemptyv",         0x029B3},  // EMPTY SET WITH RIGHT ARROW ABOVE
+        {"rang",             0x027E9},  // MATHEMATICAL RIGHT ANGLE BRACKET
+        {"Rang",             0x027EB},  // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+        {"rangd",            0x02992},  // RIGHT ANGLE BRACKET WITH DOT
+        {"range",            0x029A5},  // REVERSED ANGLE WITH UNDERBAR
+        {"rangle",           0x027E9},  // MATHEMATICAL RIGHT ANGLE BRACKET
+        {"raquo",            0x000BB},  // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+        {"rarr",             0x02192},  // RIGHTWARDS ARROW
+        {"Rarr",             0x021A0},  // RIGHTWARDS TWO HEADED ARROW
+        {"rArr",             0x021D2},  // RIGHTWARDS DOUBLE ARROW
+        {"rarrap",           0x02975},  // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO
+        {"rarrb",            0x021E5},  // RIGHTWARDS ARROW TO BAR
+        {"rarrbfs",          0x02920},  // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND
+        {"rarrc",            0x02933},  // WAVE ARROW POINTING DIRECTLY RIGHT
+        {"rarrfs",           0x0291E},  // RIGHTWARDS ARROW TO BLACK DIAMOND
+        {"rarrhk",           0x021AA},  // RIGHTWARDS ARROW WITH HOOK
+        {"rarrlp",           0x021AC},  // RIGHTWARDS ARROW WITH LOOP
+        {"rarrpl",           0x02945},  // RIGHTWARDS ARROW WITH PLUS BELOW
+        {"rarrsim",          0x02974},  // RIGHTWARDS ARROW ABOVE TILDE OPERATOR
+        {"rarrtl",           0x021A3},  // RIGHTWARDS ARROW WITH TAIL
+        {"Rarrtl",           0x02916},  // RIGHTWARDS TWO-HEADED ARROW WITH TAIL
+        {"rarrw",            0x0219D},  // RIGHTWARDS WAVE ARROW
+        {"ratail",           0x0291A},  // RIGHTWARDS ARROW-TAIL
+        {"rAtail",           0x0291C},  // RIGHTWARDS DOUBLE ARROW-TAIL
+        {"ratio",            0x02236},  // RATIO
+        {"rationals",        0x0211A},  // DOUBLE-STRUCK CAPITAL Q
+        {"rbarr",            0x0290D},  // RIGHTWARDS DOUBLE DASH ARROW
+        {"rBarr",            0x0290F},  // RIGHTWARDS TRIPLE DASH ARROW
+        {"RBarr",            0x02910},  // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW
+        {"rbbrk",            0x02773},  // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
+        {"rbrace",           0x0007D},  // RIGHT CURLY BRACKET
+        {"rbrack",           0x0005D},  // RIGHT SQUARE BRACKET
+        {"rbrke",            0x0298C},  // RIGHT SQUARE BRACKET WITH UNDERBAR
+        {"rbrksld",          0x0298E},  // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+        {"rbrkslu",          0x02990},  // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
+        {"Rcaron",           0x00158},  // LATIN CAPITAL LETTER R WITH CARON
+        {"rcaron",           0x00159},  // LATIN SMALL LETTER R WITH CARON
+        {"Rcedil",           0x00156},  // LATIN CAPITAL LETTER R WITH CEDILLA
+        {"rcedil",           0x00157},  // LATIN SMALL LETTER R WITH CEDILLA
+        {"rceil",            0x02309},  // RIGHT CEILING
+        {"rcub",             0x0007D},  // RIGHT CURLY BRACKET
+        {"Rcy",              0x00420},  // CYRILLIC CAPITAL LETTER ER
+        {"rcy",              0x00440},  // CYRILLIC SMALL LETTER ER
+        {"rdca",             0x02937},  // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS
+        {"rdldhar",          0x02969},  // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN
+        {"rdquo",            0x0201D},  // RIGHT DOUBLE QUOTATION MARK
+        {"rdquor",           0x0201D},  // RIGHT DOUBLE QUOTATION MARK
+        {"rdsh",             0x021B3},  // DOWNWARDS ARROW WITH TIP RIGHTWARDS
+        {"Re",               0x0211C},  // BLACK-LETTER CAPITAL R
+        {"real",             0x0211C},  // BLACK-LETTER CAPITAL R
+        {"realine",          0x0211B},  // SCRIPT CAPITAL R
+        {"realpart",         0x0211C},  // BLACK-LETTER CAPITAL R
+        {"reals",            0x0211D},  // DOUBLE-STRUCK CAPITAL R
+        {"rect",             0x025AD},  // WHITE RECTANGLE
+        {"reg",              0x000AE},  // REGISTERED SIGN
+        {"REG",              0x000AE},  // REGISTERED SIGN
+        {"ReverseElement",   0x0220B},  // CONTAINS AS MEMBER
+        {"ReverseEquilibrium", 0x021CB},  // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
+        {"ReverseUpEquilibrium", 0x0296F},  // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
+        {"rfisht",           0x0297D},  // RIGHT FISH TAIL
+        {"rfloor",           0x0230B},  // RIGHT FLOOR
+        {"Rfr",              0x0211C},  // BLACK-LETTER CAPITAL R
+        {"rfr",              0x1D52F},  // MATHEMATICAL FRAKTUR SMALL R
+        {"Rgr",              0x003A1},  // GREEK CAPITAL LETTER RHO
+        {"rgr",              0x003C1},  // GREEK SMALL LETTER RHO
+        {"rHar",             0x02964},  // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN
+        {"rhard",            0x021C1},  // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
+        {"rharu",            0x021C0},  // RIGHTWARDS HARPOON WITH BARB UPWARDS
+        {"rharul",           0x0296C},  // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH
+        {"Rho",              0x003A1},  // GREEK CAPITAL LETTER RHO
+        {"rho",              0x003C1},  // GREEK SMALL LETTER RHO
+        {"rhov",             0x003F1},  // GREEK RHO SYMBOL
+        {"RightAngleBracket", 0x027E9},  // MATHEMATICAL RIGHT ANGLE BRACKET
+        {"rightarrow",       0x02192},  // RIGHTWARDS ARROW
+        {"RightArrow",       0x02192},  // RIGHTWARDS ARROW
+        {"Rightarrow",       0x021D2},  // RIGHTWARDS DOUBLE ARROW
+        {"RightArrowBar",    0x021E5},  // RIGHTWARDS ARROW TO BAR
+        {"RightArrowLeftArrow", 0x021C4},  // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
+        {"rightarrowtail",   0x021A3},  // RIGHTWARDS ARROW WITH TAIL
+        {"RightCeiling",     0x02309},  // RIGHT CEILING
+        {"RightDoubleBracket", 0x027E7},  // MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+        {"RightDownTeeVector", 0x0295D},  // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR
+        {"RightDownVector",  0x021C2},  // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
+        {"RightDownVectorBar", 0x02955},  // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR
+        {"RightFloor",       0x0230B},  // RIGHT FLOOR
+        {"rightharpoondown", 0x021C1},  // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
+        {"rightharpoonup",   0x021C0},  // RIGHTWARDS HARPOON WITH BARB UPWARDS
+        {"rightleftarrows",  0x021C4},  // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
+        {"rightleftharpoons", 0x021CC},  // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
+        {"rightrightarrows", 0x021C9},  // RIGHTWARDS PAIRED ARROWS
+        {"rightsquigarrow",  0x0219D},  // RIGHTWARDS WAVE ARROW
+        {"RightTee",         0x022A2},  // RIGHT TACK
+        {"RightTeeArrow",    0x021A6},  // RIGHTWARDS ARROW FROM BAR
+        {"RightTeeVector",   0x0295B},  // RIGHTWARDS HARPOON WITH BARB UP FROM BAR
+        {"rightthreetimes",  0x022CC},  // RIGHT SEMIDIRECT PRODUCT
+        {"RightTriangle",    0x022B3},  // CONTAINS AS NORMAL SUBGROUP
+        {"RightTriangleBar", 0x029D0},  // VERTICAL BAR BESIDE RIGHT TRIANGLE
+        {"RightTriangleEqual", 0x022B5},  // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
+        {"RightUpDownVector", 0x0294F},  // UP BARB RIGHT DOWN BARB RIGHT HARPOON
+        {"RightUpTeeVector", 0x0295C},  // UPWARDS HARPOON WITH BARB RIGHT FROM BAR
+        {"RightUpVector",    0x021BE},  // UPWARDS HARPOON WITH BARB RIGHTWARDS
+        {"RightUpVectorBar", 0x02954},  // UPWARDS HARPOON WITH BARB RIGHT TO BAR
+        {"RightVector",      0x021C0},  // RIGHTWARDS HARPOON WITH BARB UPWARDS
+        {"RightVectorBar",   0x02953},  // RIGHTWARDS HARPOON WITH BARB UP TO BAR
+        {"ring",             0x002DA},  // RING ABOVE
+        {"risingdotseq",     0x02253},  // IMAGE OF OR APPROXIMATELY EQUAL TO
+        {"rlarr",            0x021C4},  // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
+        {"rlhar",            0x021CC},  // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
+        {"rlm",              0x0200F},  // RIGHT-TO-LEFT MARK
+        {"rmoust",           0x023B1},  // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION
+        {"rmoustache",       0x023B1},  // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION
+        {"rnmid",            0x02AEE},  // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH
+        {"roang",            0x027ED},  // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
+        {"roarr",            0x021FE},  // RIGHTWARDS OPEN-HEADED ARROW
+        {"robrk",            0x027E7},  // MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+        {"ropar",            0x02986},  // RIGHT WHITE PARENTHESIS
+        {"Ropf",             0x0211D},  // DOUBLE-STRUCK CAPITAL R
+        {"ropf",             0x1D563},  // MATHEMATICAL DOUBLE-STRUCK SMALL R
+        {"roplus",           0x02A2E},  // PLUS SIGN IN RIGHT HALF CIRCLE
+        {"rotimes",          0x02A35},  // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE
+        {"RoundImplies",     0x02970},  // RIGHT DOUBLE ARROW WITH ROUNDED HEAD
+        {"rpar",             0x00029},  // RIGHT PARENTHESIS
+        {"rpargt",           0x02994},  // RIGHT ARC GREATER-THAN BRACKET
+        {"rppolint",         0x02A12},  // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE
+        {"rrarr",            0x021C9},  // RIGHTWARDS PAIRED ARROWS
+        {"Rrightarrow",      0x021DB},  // RIGHTWARDS TRIPLE ARROW
+        {"rsaquo",           0x0203A},  // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+        {"Rscr",             0x0211B},  // SCRIPT CAPITAL R
+        {"rscr",             0x1D4C7},  // MATHEMATICAL SCRIPT SMALL R
+        {"rsh",              0x021B1},  // UPWARDS ARROW WITH TIP RIGHTWARDS
+        {"Rsh",              0x021B1},  // UPWARDS ARROW WITH TIP RIGHTWARDS
+        {"rsqb",             0x0005D},  // RIGHT SQUARE BRACKET
+        {"rsquo",            0x02019},  // RIGHT SINGLE QUOTATION MARK
+        {"rsquor",           0x02019},  // RIGHT SINGLE QUOTATION MARK
+        {"rthree",           0x022CC},  // RIGHT SEMIDIRECT PRODUCT
+        {"rtimes",           0x022CA},  // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT
+        {"rtri",             0x025B9},  // WHITE RIGHT-POINTING SMALL TRIANGLE
+        {"rtrie",            0x022B5},  // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
+        {"rtrif",            0x025B8},  // BLACK RIGHT-POINTING SMALL TRIANGLE
+        {"rtriltri",         0x029CE},  // RIGHT TRIANGLE ABOVE LEFT TRIANGLE
+        {"RuleDelayed",      0x029F4},  // RULE-DELAYED
+        {"ruluhar",          0x02968},  // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP
+        {"rx",               0x0211E},  // PRESCRIPTION TAKE
+        {NULL,               0}
+};
+
+static NameId namesS[]={
+        {"Sacute",           0x0015A},  // LATIN CAPITAL LETTER S WITH ACUTE
+        {"sacute",           0x0015B},  // LATIN SMALL LETTER S WITH ACUTE
+        {"sbquo",            0x0201A},  // SINGLE LOW-9 QUOTATION MARK
+        {"sc",               0x0227B},  // SUCCEEDS
+        {"Sc",               0x02ABC},  // DOUBLE SUCCEEDS
+        {"scap",             0x02AB8},  // SUCCEEDS ABOVE ALMOST EQUAL TO
+        {"Scaron",           0x00160},  // LATIN CAPITAL LETTER S WITH CARON
+        {"scaron",           0x00161},  // LATIN SMALL LETTER S WITH CARON
+        {"sccue",            0x0227D},  // SUCCEEDS OR EQUAL TO
+        {"sce",              0x02AB0},  // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
+        {"scE",              0x02AB4},  // SUCCEEDS ABOVE EQUALS SIGN
+        {"Scedil",           0x0015E},  // LATIN CAPITAL LETTER S WITH CEDILLA
+        {"scedil",           0x0015F},  // LATIN SMALL LETTER S WITH CEDILLA
+        {"Scirc",            0x0015C},  // LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+        {"scirc",            0x0015D},  // LATIN SMALL LETTER S WITH CIRCUMFLEX
+        {"scnap",            0x02ABA},  // SUCCEEDS ABOVE NOT ALMOST EQUAL TO
+        {"scnE",             0x02AB6},  // SUCCEEDS ABOVE NOT EQUAL TO
+        {"scnsim",           0x022E9},  // SUCCEEDS BUT NOT EQUIVALENT TO
+        {"scpolint",         0x02A13},  // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE
+        {"scsim",            0x0227F},  // SUCCEEDS OR EQUIVALENT TO
+        {"Scy",              0x00421},  // CYRILLIC CAPITAL LETTER ES
+        {"scy",              0x00441},  // CYRILLIC SMALL LETTER ES
+        {"sdot",             0x022C5},  // DOT OPERATOR
+        {"sdotb",            0x022A1},  // SQUARED DOT OPERATOR
+        {"sdote",            0x02A66},  // EQUALS SIGN WITH DOT BELOW
+        {"searhk",           0x02925},  // SOUTH EAST ARROW WITH HOOK
+        {"searr",            0x02198},  // SOUTH EAST ARROW
+        {"seArr",            0x021D8},  // SOUTH EAST DOUBLE ARROW
+        {"searrow",          0x02198},  // SOUTH EAST ARROW
+        {"sect",             0x000A7},  // SECTION SIGN
+        {"semi",             0x0003B},  // SEMICOLON
+        {"seswar",           0x02929},  // SOUTH EAST ARROW AND SOUTH WEST ARROW
+        {"setminus",         0x02216},  // SET MINUS
+        {"setmn",            0x02216},  // SET MINUS
+        {"sext",             0x02736},  // SIX POINTED BLACK STAR
+        {"sfgr",             0x003C2},  // GREEK SMALL LETTER FINAL SIGMA
+        {"Sfr",              0x1D516},  // MATHEMATICAL FRAKTUR CAPITAL S
+        {"sfr",              0x1D530},  // MATHEMATICAL FRAKTUR SMALL S
+        {"sfrown",           0x02322},  // FROWN
+        {"Sgr",              0x003A3},  // GREEK CAPITAL LETTER SIGMA
+        {"sgr",              0x003C3},  // GREEK SMALL LETTER SIGMA
+        {"sharp",            0x0266F},  // MUSIC SHARP SIGN
+        {"SHCHcy",           0x00429},  // CYRILLIC CAPITAL LETTER SHCHA
+        {"shchcy",           0x00449},  // CYRILLIC SMALL LETTER SHCHA
+        {"SHcy",             0x00428},  // CYRILLIC CAPITAL LETTER SHA
+        {"shcy",             0x00448},  // CYRILLIC SMALL LETTER SHA
+        {"ShortDownArrow",   0x02193},  // DOWNWARDS ARROW
+        {"ShortLeftArrow",   0x02190},  // LEFTWARDS ARROW
+        {"shortmid",         0x02223},  // DIVIDES
+        {"shortparallel",    0x02225},  // PARALLEL TO
+        {"ShortRightArrow",  0x02192},  // RIGHTWARDS ARROW
+        {"ShortUpArrow",     0x02191},  // UPWARDS ARROW
+        {"shy",              0x000AD},  // SOFT HYPHEN
+        {"Sigma",            0x003A3},  // GREEK CAPITAL LETTER SIGMA
+        {"sigma",            0x003C3},  // GREEK SMALL LETTER SIGMA
+        {"sigmaf",           0x003C2},  // GREEK SMALL LETTER FINAL SIGMA
+        {"sigmav",           0x003C2},  // GREEK SMALL LETTER FINAL SIGMA
+        {"sim",              0x0223C},  // TILDE OPERATOR
+        {"simdot",           0x02A6A},  // TILDE OPERATOR WITH DOT ABOVE
+        {"sime",             0x02243},  // ASYMPTOTICALLY EQUAL TO
+        {"simeq",            0x02243},  // ASYMPTOTICALLY EQUAL TO
+        {"simg",             0x02A9E},  // SIMILAR OR GREATER-THAN
+        {"simgE",            0x02AA0},  // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN
+        {"siml",             0x02A9D},  // SIMILAR OR LESS-THAN
+        {"simlE",            0x02A9F},  // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN
+        {"simne",            0x02246},  // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO
+        {"simplus",          0x02A24},  // PLUS SIGN WITH TILDE ABOVE
+        {"simrarr",          0x02972},  // TILDE OPERATOR ABOVE RIGHTWARDS ARROW
+        {"slarr",            0x02190},  // LEFTWARDS ARROW
+        {"SmallCircle",      0x02218},  // RING OPERATOR
+        {"smallsetminus",    0x02216},  // SET MINUS
+        {"smashp",           0x02A33},  // SMASH PRODUCT
+        {"smeparsl",         0x029E4},  // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE
+        {"smid",             0x02223},  // DIVIDES
+        {"smile",            0x02323},  // SMILE
+        {"smt",              0x02AAA},  // SMALLER THAN
+        {"smte",             0x02AAC},  // SMALLER THAN OR EQUAL TO
+//      "smtes",            0x02AAC;0x0FE00},  // SMALLER THAN OR slanted EQUAL
+        {"SOFTcy",           0x0042C},  // CYRILLIC CAPITAL LETTER SOFT SIGN
+        {"softcy",           0x0044C},  // CYRILLIC SMALL LETTER SOFT SIGN
+        {"sol",              0x0002F},  // SOLIDUS
+        {"solb",             0x029C4},  // SQUARED RISING DIAGONAL SLASH
+        {"solbar",           0x0233F},  // APL FUNCTIONAL SYMBOL SLASH BAR
+        {"Sopf",             0x1D54A},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL S
+        {"sopf",             0x1D564},  // MATHEMATICAL DOUBLE-STRUCK SMALL S
+        {"spades",           0x02660},  // BLACK SPADE SUIT
+        {"spadesuit",        0x02660},  // BLACK SPADE SUIT
+        {"spar",             0x02225},  // PARALLEL TO
+        {"sqcap",            0x02293},  // SQUARE CAP
+//      "sqcaps",           0x02293;0x0FE00},  // SQUARE CAP with serifs
+        {"sqcup",            0x02294},  // SQUARE CUP
+//      "sqcups",           0x02294;0x0FE00},  // SQUARE CUP with serifs
+        {"Sqrt",             0x0221A},  // SQUARE ROOT
+        {"sqsub",            0x0228F},  // SQUARE IMAGE OF
+        {"sqsube",           0x02291},  // SQUARE IMAGE OF OR EQUAL TO
+        {"sqsubset",         0x0228F},  // SQUARE IMAGE OF
+        {"sqsubseteq",       0x02291},  // SQUARE IMAGE OF OR EQUAL TO
+        {"sqsup",            0x02290},  // SQUARE ORIGINAL OF
+        {"sqsupe",           0x02292},  // SQUARE ORIGINAL OF OR EQUAL TO
+        {"sqsupset",         0x02290},  // SQUARE ORIGINAL OF
+        {"sqsupseteq",       0x02292},  // SQUARE ORIGINAL OF OR EQUAL TO
+        {"squ",              0x025A1},  // WHITE SQUARE
+        {"square",           0x025A1},  // WHITE SQUARE
+        {"Square",           0x025A1},  // WHITE SQUARE
+        {"SquareIntersection", 0x02293},  // SQUARE CAP
+        {"SquareSubset",     0x0228F},  // SQUARE IMAGE OF
+        {"SquareSubsetEqual", 0x02291},  // SQUARE IMAGE OF OR EQUAL TO
+        {"SquareSuperset",   0x02290},  // SQUARE ORIGINAL OF
+        {"SquareSupersetEqual", 0x02292},  // SQUARE ORIGINAL OF OR EQUAL TO
+        {"SquareUnion",      0x02294},  // SQUARE CUP
+        {"squarf",           0x025AA},  // BLACK SMALL SQUARE
+        {"squf",             0x025AA},  // BLACK SMALL SQUARE
+        {"srarr",            0x02192},  // RIGHTWARDS ARROW
+        {"Sscr",             0x1D4AE},  // MATHEMATICAL SCRIPT CAPITAL S
+        {"sscr",             0x1D4C8},  // MATHEMATICAL SCRIPT SMALL S
+        {"ssetmn",           0x02216},  // SET MINUS
+        {"ssmile",           0x02323},  // SMILE
+        {"sstarf",           0x022C6},  // STAR OPERATOR
+        {"Star",             0x022C6},  // STAR OPERATOR
+        {"star",             0x02606},  // WHITE STAR
+        {"starf",            0x02605},  // BLACK STAR
+        {"straightepsilon",  0x003F5},  // GREEK LUNATE EPSILON SYMBOL
+        {"straightphi",      0x003D5},  // GREEK PHI SYMBOL
+        {"strns",            0x000AF},  // MACRON
+        {"sub",              0x02282},  // SUBSET OF
+        {"Sub",              0x022D0},  // DOUBLE SUBSET
+        {"subdot",           0x02ABD},  // SUBSET WITH DOT
+        {"sube",             0x02286},  // SUBSET OF OR EQUAL TO
+        {"subE",             0x02AC5},  // SUBSET OF ABOVE EQUALS SIGN
+        {"subedot",          0x02AC3},  // SUBSET OF OR EQUAL TO WITH DOT ABOVE
+        {"submult",          0x02AC1},  // SUBSET WITH MULTIPLICATION SIGN BELOW
+        {"subne",            0x0228A},  // SUBSET OF WITH NOT EQUAL TO
+        {"subnE",            0x02ACB},  // SUBSET OF ABOVE NOT EQUAL TO
+        {"subplus",          0x02ABF},  // SUBSET WITH PLUS SIGN BELOW
+        {"subrarr",          0x02979},  // SUBSET ABOVE RIGHTWARDS ARROW
+        {"subset",           0x02282},  // SUBSET OF
+        {"Subset",           0x022D0},  // DOUBLE SUBSET
+        {"subseteq",         0x02286},  // SUBSET OF OR EQUAL TO
+        {"subseteqq",        0x02AC5},  // SUBSET OF ABOVE EQUALS SIGN
+        {"SubsetEqual",      0x02286},  // SUBSET OF OR EQUAL TO
+        {"subsetneq",        0x0228A},  // SUBSET OF WITH NOT EQUAL TO
+        {"subsetneqq",       0x02ACB},  // SUBSET OF ABOVE NOT EQUAL TO
+        {"subsim",           0x02AC7},  // SUBSET OF ABOVE TILDE OPERATOR
+        {"subsub",           0x02AD5},  // SUBSET ABOVE SUBSET
+        {"subsup",           0x02AD3},  // SUBSET ABOVE SUPERSET
+        {"succ",             0x0227B},  // SUCCEEDS
+        {"succapprox",       0x02AB8},  // SUCCEEDS ABOVE ALMOST EQUAL TO
+        {"succcurlyeq",      0x0227D},  // SUCCEEDS OR EQUAL TO
+        {"Succeeds",         0x0227B},  // SUCCEEDS
+        {"SucceedsEqual",    0x02AB0},  // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
+        {"SucceedsSlantEqual", 0x0227D},  // SUCCEEDS OR EQUAL TO
+        {"SucceedsTilde",    0x0227F},  // SUCCEEDS OR EQUIVALENT TO
+        {"succeq",           0x02AB0},  // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
+        {"succnapprox",      0x02ABA},  // SUCCEEDS ABOVE NOT ALMOST EQUAL TO
+        {"succneqq",         0x02AB6},  // SUCCEEDS ABOVE NOT EQUAL TO
+        {"succnsim",         0x022E9},  // SUCCEEDS BUT NOT EQUIVALENT TO
+        {"succsim",          0x0227F},  // SUCCEEDS OR EQUIVALENT TO
+        {"SuchThat",         0x0220B},  // CONTAINS AS MEMBER
+        {"sum",              0x02211},  // N-ARY SUMMATION
+        {"Sum",              0x02211},  // N-ARY SUMMATION
+        {"sung",             0x0266A},  // EIGHTH NOTE
+        {"sup",              0x02283},  // SUPERSET OF
+        {"Sup",              0x022D1},  // DOUBLE SUPERSET
+        {"sup1",             0x000B9},  // SUPERSCRIPT ONE
+        {"sup2",             0x000B2},  // SUPERSCRIPT TWO
+        {"sup3",             0x000B3},  // SUPERSCRIPT THREE
+        {"supdot",           0x02ABE},  // SUPERSET WITH DOT
+        {"supdsub",          0x02AD8},  // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET
+        {"supe",             0x02287},  // SUPERSET OF OR EQUAL TO
+        {"supE",             0x02AC6},  // SUPERSET OF ABOVE EQUALS SIGN
+        {"supedot",          0x02AC4},  // SUPERSET OF OR EQUAL TO WITH DOT ABOVE
+        {"Superset",         0x02283},  // SUPERSET OF
+        {"SupersetEqual",    0x02287},  // SUPERSET OF OR EQUAL TO
+        {"suphsol",          0x027C9},  // SUPERSET PRECEDING SOLIDUS
+        {"suphsub",          0x02AD7},  // SUPERSET BESIDE SUBSET
+        {"suplarr",          0x0297B},  // SUPERSET ABOVE LEFTWARDS ARROW
+        {"supmult",          0x02AC2},  // SUPERSET WITH MULTIPLICATION SIGN BELOW
+        {"supne",            0x0228B},  // SUPERSET OF WITH NOT EQUAL TO
+        {"supnE",            0x02ACC},  // SUPERSET OF ABOVE NOT EQUAL TO
+        {"supplus",          0x02AC0},  // SUPERSET WITH PLUS SIGN BELOW
+        {"supset",           0x02283},  // SUPERSET OF
+        {"Supset",           0x022D1},  // DOUBLE SUPERSET
+        {"supseteq",         0x02287},  // SUPERSET OF OR EQUAL TO
+        {"supseteqq",        0x02AC6},  // SUPERSET OF ABOVE EQUALS SIGN
+        {"supsetneq",        0x0228B},  // SUPERSET OF WITH NOT EQUAL TO
+        {"supsetneqq",       0x02ACC},  // SUPERSET OF ABOVE NOT EQUAL TO
+        {"supsim",           0x02AC8},  // SUPERSET OF ABOVE TILDE OPERATOR
+        {"supsub",           0x02AD4},  // SUPERSET ABOVE SUBSET
+        {"supsup",           0x02AD6},  // SUPERSET ABOVE SUPERSET
+        {"swarhk",           0x02926},  // SOUTH WEST ARROW WITH HOOK
+        {"swarr",            0x02199},  // SOUTH WEST ARROW
+        {"swArr",            0x021D9},  // SOUTH WEST DOUBLE ARROW
+        {"swarrow",          0x02199},  // SOUTH WEST ARROW
+        {"swnwar",           0x0292A},  // SOUTH WEST ARROW AND NORTH WEST ARROW
+        {"szlig",            0x000DF},  // LATIN SMALL LETTER SHARP S
+        {NULL,               0}
+};
+
+static NameId namesT[]={
+        {"Tab",              0x00009},  // CHARACTER TABULATION
+        {"target",           0x02316},  // POSITION INDICATOR
+        {"Tau",              0x003A4},  // GREEK CAPITAL LETTER TAU
+        {"tau",              0x003C4},  // GREEK SMALL LETTER TAU
+        {"tbrk",             0x023B4},  // TOP SQUARE BRACKET
+        {"Tcaron",           0x00164},  // LATIN CAPITAL LETTER T WITH CARON
+        {"tcaron",           0x00165},  // LATIN SMALL LETTER T WITH CARON
+        {"Tcedil",           0x00162},  // LATIN CAPITAL LETTER T WITH CEDILLA
+        {"tcedil",           0x00163},  // LATIN SMALL LETTER T WITH CEDILLA
+        {"Tcy",              0x00422},  // CYRILLIC CAPITAL LETTER TE
+        {"tcy",              0x00442},  // CYRILLIC SMALL LETTER TE
+        {"tdot",             0x020DB},  // COMBINING THREE DOTS ABOVE
+        {"telrec",           0x02315},  // TELEPHONE RECORDER
+        {"Tfr",              0x1D517},  // MATHEMATICAL FRAKTUR CAPITAL T
+        {"tfr",              0x1D531},  // MATHEMATICAL FRAKTUR SMALL T
+        {"Tgr",              0x003A4},  // GREEK CAPITAL LETTER TAU
+        {"tgr",              0x003C4},  // GREEK SMALL LETTER TAU
+        {"there4",           0x02234},  // THEREFORE
+        {"therefore",        0x02234},  // THEREFORE
+        {"Therefore",        0x02234},  // THEREFORE
+        {"Theta",            0x00398},  // GREEK CAPITAL LETTER THETA
+        {"theta",            0x003B8},  // GREEK SMALL LETTER THETA
+        {"thetasym",         0x003D1},  // GREEK THETA SYMBOL
+        {"thetav",           0x003D1},  // GREEK THETA SYMBOL
+        {"THgr",             0x00398},  // GREEK CAPITAL LETTER THETA
+        {"thgr",             0x003B8},  // GREEK SMALL LETTER THETA
+        {"thickapprox",      0x02248},  // ALMOST EQUAL TO
+        {"thicksim",         0x0223C},  // TILDE OPERATOR
+//      "ThickSpace",       0x0205F;0x0200A},  // space of width 5/18 em
+        {"thinsp",           0x02009},  // THIN SPACE
+        {"ThinSpace",        0x02009},  // THIN SPACE
+        {"thkap",            0x02248},  // ALMOST EQUAL TO
+        {"thksim",           0x0223C},  // TILDE OPERATOR
+        {"THORN",            0x000DE},  // LATIN CAPITAL LETTER THORN
+        {"thorn",            0x000FE},  // LATIN SMALL LETTER THORN
+        {"tilde",            0x002DC},  // SMALL TILDE
+        {"Tilde",            0x0223C},  // TILDE OPERATOR
+        {"TildeEqual",       0x02243},  // ASYMPTOTICALLY EQUAL TO
+        {"TildeFullEqual",   0x02245},  // APPROXIMATELY EQUAL TO
+        {"TildeTilde",       0x02248},  // ALMOST EQUAL TO
+        {"times",            0x000D7},  // MULTIPLICATION SIGN
+        {"timesb",           0x022A0},  // SQUARED TIMES
+        {"timesbar",         0x02A31},  // MULTIPLICATION SIGN WITH UNDERBAR
+        {"timesd",           0x02A30},  // MULTIPLICATION SIGN WITH DOT ABOVE
+        {"tint",             0x0222D},  // TRIPLE INTEGRAL
+        {"toea",             0x02928},  // NORTH EAST ARROW AND SOUTH EAST ARROW
+        {"top",              0x022A4},  // DOWN TACK
+        {"topbot",           0x02336},  // APL FUNCTIONAL SYMBOL I-BEAM
+        {"topcir",           0x02AF1},  // DOWN TACK WITH CIRCLE BELOW
+        {"Topf",             0x1D54B},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL T
+        {"topf",             0x1D565},  // MATHEMATICAL DOUBLE-STRUCK SMALL T
+        {"topfork",          0x02ADA},  // PITCHFORK WITH TEE TOP
+        {"tosa",             0x02929},  // SOUTH EAST ARROW AND SOUTH WEST ARROW
+        {"tprime",           0x02034},  // TRIPLE PRIME
+        {"trade",            0x02122},  // TRADE MARK SIGN
+        {"TRADE",            0x02122},  // TRADE MARK SIGN
+        {"triangle",         0x025B5},  // WHITE UP-POINTING SMALL TRIANGLE
+        {"triangledown",     0x025BF},  // WHITE DOWN-POINTING SMALL TRIANGLE
+        {"triangleleft",     0x025C3},  // WHITE LEFT-POINTING SMALL TRIANGLE
+        {"trianglelefteq",   0x022B4},  // NORMAL SUBGROUP OF OR EQUAL TO
+        {"triangleq",        0x0225C},  // DELTA EQUAL TO
+        {"triangleright",    0x025B9},  // WHITE RIGHT-POINTING SMALL TRIANGLE
+        {"trianglerighteq",  0x022B5},  // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
+        {"tridot",           0x025EC},  // WHITE UP-POINTING TRIANGLE WITH DOT
+        {"trie",             0x0225C},  // DELTA EQUAL TO
+        {"triminus",         0x02A3A},  // MINUS SIGN IN TRIANGLE
+        {"TripleDot",        0x020DB},  // COMBINING THREE DOTS ABOVE
+        {"triplus",          0x02A39},  // PLUS SIGN IN TRIANGLE
+        {"trisb",            0x029CD},  // TRIANGLE WITH SERIFS AT BOTTOM
+        {"tritime",          0x02A3B},  // MULTIPLICATION SIGN IN TRIANGLE
+        {"trpezium",         0x023E2},  // WHITE TRAPEZIUM
+        {"Tscr",             0x1D4AF},  // MATHEMATICAL SCRIPT CAPITAL T
+        {"tscr",             0x1D4C9},  // MATHEMATICAL SCRIPT SMALL T
+        {"TScy",             0x00426},  // CYRILLIC CAPITAL LETTER TSE
+        {"tscy",             0x00446},  // CYRILLIC SMALL LETTER TSE
+        {"TSHcy",            0x0040B},  // CYRILLIC CAPITAL LETTER TSHE
+        {"tshcy",            0x0045B},  // CYRILLIC SMALL LETTER TSHE
+        {"Tstrok",           0x00166},  // LATIN CAPITAL LETTER T WITH STROKE
+        {"tstrok",           0x00167},  // LATIN SMALL LETTER T WITH STROKE
+        {"twixt",            0x0226C},  // BETWEEN
+        {"twoheadleftarrow", 0x0219E},  // LEFTWARDS TWO HEADED ARROW
+        {"twoheadrightarrow", 0x021A0},  // RIGHTWARDS TWO HEADED ARROW
+        {NULL,               0}
+};
+
+static NameId namesU[]={
+        {"Uacgr",            0x0038E},  // GREEK CAPITAL LETTER UPSILON WITH TONOS
+        {"uacgr",            0x003CD},  // GREEK SMALL LETTER UPSILON WITH TONOS
+        {"Uacute",           0x000DA},  // LATIN CAPITAL LETTER U WITH ACUTE
+        {"uacute",           0x000FA},  // LATIN SMALL LETTER U WITH ACUTE
+        {"uarr",             0x02191},  // UPWARDS ARROW
+        {"Uarr",             0x0219F},  // UPWARDS TWO HEADED ARROW
+        {"uArr",             0x021D1},  // UPWARDS DOUBLE ARROW
+        {"Uarrocir",         0x02949},  // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE
+        {"Ubrcy",            0x0040E},  // CYRILLIC CAPITAL LETTER SHORT U
+        {"ubrcy",            0x0045E},  // CYRILLIC SMALL LETTER SHORT U
+        {"Ubreve",           0x0016C},  // LATIN CAPITAL LETTER U WITH BREVE
+        {"ubreve",           0x0016D},  // LATIN SMALL LETTER U WITH BREVE
+        {"Ucirc",            0x000DB},  // LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+        {"ucirc",            0x000FB},  // LATIN SMALL LETTER U WITH CIRCUMFLEX
+        {"Ucy",              0x00423},  // CYRILLIC CAPITAL LETTER U
+        {"ucy",              0x00443},  // CYRILLIC SMALL LETTER U
+        {"udarr",            0x021C5},  // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW
+        {"Udblac",           0x00170},  // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+        {"udblac",           0x00171},  // LATIN SMALL LETTER U WITH DOUBLE ACUTE
+        {"udhar",            0x0296E},  // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
+        {"udiagr",           0x003B0},  // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+        {"Udigr",            0x003AB},  // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+        {"udigr",            0x003CB},  // GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+        {"ufisht",           0x0297E},  // UP FISH TAIL
+        {"Ufr",              0x1D518},  // MATHEMATICAL FRAKTUR CAPITAL U
+        {"ufr",              0x1D532},  // MATHEMATICAL FRAKTUR SMALL U
+        {"Ugr",              0x003A5},  // GREEK CAPITAL LETTER UPSILON
+        {"ugr",              0x003C5},  // GREEK SMALL LETTER UPSILON
+        {"Ugrave",           0x000D9},  // LATIN CAPITAL LETTER U WITH GRAVE
+        {"ugrave",           0x000F9},  // LATIN SMALL LETTER U WITH GRAVE
+        {"uHar",             0x02963},  // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
+        {"uharl",            0x021BF},  // UPWARDS HARPOON WITH BARB LEFTWARDS
+        {"uharr",            0x021BE},  // UPWARDS HARPOON WITH BARB RIGHTWARDS
+        {"uhblk",            0x02580},  // UPPER HALF BLOCK
+        {"ulcorn",           0x0231C},  // TOP LEFT CORNER
+        {"ulcorner",         0x0231C},  // TOP LEFT CORNER
+        {"ulcrop",           0x0230F},  // TOP LEFT CROP
+        {"ultri",            0x025F8},  // UPPER LEFT TRIANGLE
+        {"Umacr",            0x0016A},  // LATIN CAPITAL LETTER U WITH MACRON
+        {"umacr",            0x0016B},  // LATIN SMALL LETTER U WITH MACRON
+        {"uml",              0x000A8},  // DIAERESIS
+        {"UnderBar",         0x0005F},  // LOW LINE
+        {"UnderBrace",       0x023DF},  // BOTTOM CURLY BRACKET
+        {"UnderBracket",     0x023B5},  // BOTTOM SQUARE BRACKET
+        {"UnderParenthesis", 0x023DD},  // BOTTOM PARENTHESIS
+        {"Union",            0x022C3},  // N-ARY UNION
+        {"UnionPlus",        0x0228E},  // MULTISET UNION
+        {"Uogon",            0x00172},  // LATIN CAPITAL LETTER U WITH OGONEK
+        {"uogon",            0x00173},  // LATIN SMALL LETTER U WITH OGONEK
+        {"Uopf",             0x1D54C},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL U
+        {"uopf",             0x1D566},  // MATHEMATICAL DOUBLE-STRUCK SMALL U
+        {"uparrow",          0x02191},  // UPWARDS ARROW
+        {"UpArrow",          0x02191},  // UPWARDS ARROW
+        {"Uparrow",          0x021D1},  // UPWARDS DOUBLE ARROW
+        {"UpArrowBar",       0x02912},  // UPWARDS ARROW TO BAR
+        {"UpArrowDownArrow", 0x021C5},  // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW
+        {"updownarrow",      0x02195},  // UP DOWN ARROW
+        {"UpDownArrow",      0x02195},  // UP DOWN ARROW
+        {"Updownarrow",      0x021D5},  // UP DOWN DOUBLE ARROW
+        {"UpEquilibrium",    0x0296E},  // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
+        {"upharpoonleft",    0x021BF},  // UPWARDS HARPOON WITH BARB LEFTWARDS
+        {"upharpoonright",   0x021BE},  // UPWARDS HARPOON WITH BARB RIGHTWARDS
+        {"uplus",            0x0228E},  // MULTISET UNION
+        {"UpperLeftArrow",   0x02196},  // NORTH WEST ARROW
+        {"UpperRightArrow",  0x02197},  // NORTH EAST ARROW
+        {"upsi",             0x003C5},  // GREEK SMALL LETTER UPSILON
+        {"Upsi",             0x003D2},  // GREEK UPSILON WITH HOOK SYMBOL
+        {"upsih",            0x003D2},  // GREEK UPSILON WITH HOOK SYMBOL
+        {"Upsilon",          0x003A5},  // GREEK CAPITAL LETTER UPSILON
+        {"upsilon",          0x003C5},  // GREEK SMALL LETTER UPSILON
+        {"UpTee",            0x022A5},  // UP TACK
+        {"UpTeeArrow",       0x021A5},  // UPWARDS ARROW FROM BAR
+        {"upuparrows",       0x021C8},  // UPWARDS PAIRED ARROWS
+        {"urcorn",           0x0231D},  // TOP RIGHT CORNER
+        {"urcorner",         0x0231D},  // TOP RIGHT CORNER
+        {"urcrop",           0x0230E},  // TOP RIGHT CROP
+        {"Uring",            0x0016E},  // LATIN CAPITAL LETTER U WITH RING ABOVE
+        {"uring",            0x0016F},  // LATIN SMALL LETTER U WITH RING ABOVE
+        {"urtri",            0x025F9},  // UPPER RIGHT TRIANGLE
+        {"Uscr",             0x1D4B0},  // MATHEMATICAL SCRIPT CAPITAL U
+        {"uscr",             0x1D4CA},  // MATHEMATICAL SCRIPT SMALL U
+        {"utdot",            0x022F0},  // UP RIGHT DIAGONAL ELLIPSIS
+        {"Utilde",           0x00168},  // LATIN CAPITAL LETTER U WITH TILDE
+        {"utilde",           0x00169},  // LATIN SMALL LETTER U WITH TILDE
+        {"utri",             0x025B5},  // WHITE UP-POINTING SMALL TRIANGLE
+        {"utrif",            0x025B4},  // BLACK UP-POINTING SMALL TRIANGLE
+        {"uuarr",            0x021C8},  // UPWARDS PAIRED ARROWS
+        {"Uuml",             0x000DC},  // LATIN CAPITAL LETTER U WITH DIAERESIS
+        {"uuml",             0x000FC},  // LATIN SMALL LETTER U WITH DIAERESIS
+        {"uwangle",          0x029A7},  // OBLIQUE ANGLE OPENING DOWN
+        {NULL,               0}
+};
+
+static NameId namesV[]={
+        {"vangrt",           0x0299C},  // RIGHT ANGLE VARIANT WITH SQUARE
+        {"varepsilon",       0x003F5},  // GREEK LUNATE EPSILON SYMBOL
+        {"varkappa",         0x003F0},  // GREEK KAPPA SYMBOL
+        {"varnothing",       0x02205},  // EMPTY SET
+        {"varphi",           0x003D5},  // GREEK PHI SYMBOL
+        {"varpi",            0x003D6},  // GREEK PI SYMBOL
+        {"varpropto",        0x0221D},  // PROPORTIONAL TO
+        {"varr",             0x02195},  // UP DOWN ARROW
+        {"vArr",             0x021D5},  // UP DOWN DOUBLE ARROW
+        {"varrho",           0x003F1},  // GREEK RHO SYMBOL
+        {"varsigma",         0x003C2},  // GREEK SMALL LETTER FINAL SIGMA
+//      "varsubsetneq",     0x0228A;0x0FE00},  // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
+//      "varsubsetneqq",    0x02ACB;0x0FE00},  // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
+//      "varsupsetneq",     0x0228B;0x0FE00},  // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
+//      "varsupsetneqq",    0x02ACC;0x0FE00},  // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
+        {"vartheta",         0x003D1},  // GREEK THETA SYMBOL
+        {"vartriangleleft",  0x022B2},  // NORMAL SUBGROUP OF
+        {"vartriangleright", 0x022B3},  // CONTAINS AS NORMAL SUBGROUP
+        {"vBar",             0x02AE8},  // SHORT UP TACK WITH UNDERBAR
+        {"Vbar",             0x02AEB},  // DOUBLE UP TACK
+        {"vBarv",            0x02AE9},  // SHORT UP TACK ABOVE SHORT DOWN TACK
+        {"Vcy",              0x00412},  // CYRILLIC CAPITAL LETTER VE
+        {"vcy",              0x00432},  // CYRILLIC SMALL LETTER VE
+        {"vdash",            0x022A2},  // RIGHT TACK
+        {"vDash",            0x022A8},  // TRUE
+        {"Vdash",            0x022A9},  // FORCES
+        {"VDash",            0x022AB},  // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
+        {"Vdashl",           0x02AE6},  // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL
+        {"vee",              0x02228},  // LOGICAL OR
+        {"Vee",              0x022C1},  // N-ARY LOGICAL OR
+        {"veebar",           0x022BB},  // XOR
+        {"veeeq",            0x0225A},  // EQUIANGULAR TO
+        {"vellip",           0x022EE},  // VERTICAL ELLIPSIS
+        {"verbar",           0x0007C},  // VERTICAL LINE
+        {"Verbar",           0x02016},  // DOUBLE VERTICAL LINE
+        {"vert",             0x0007C},  // VERTICAL LINE
+        {"Vert",             0x02016},  // DOUBLE VERTICAL LINE
+        {"VerticalBar",      0x02223},  // DIVIDES
+        {"VerticalLine",     0x0007C},  // VERTICAL LINE
+        {"VerticalSeparator", 0x02758},  // LIGHT VERTICAL BAR
+        {"VerticalTilde",    0x02240},  // WREATH PRODUCT
+        {"VeryThinSpace",    0x0200A},  // HAIR SPACE
+        {"Vfr",              0x1D519},  // MATHEMATICAL FRAKTUR CAPITAL V
+        {"vfr",              0x1D533},  // MATHEMATICAL FRAKTUR SMALL V
+        {"vltri",            0x022B2},  // NORMAL SUBGROUP OF
+//      "vnsub",            0x02282;0x020D2},  // SUBSET OF with vertical line
+//      "vnsup",            0x02283;0x020D2},  // SUPERSET OF with vertical line
+        {"Vopf",             0x1D54D},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL V
+        {"vopf",             0x1D567},  // MATHEMATICAL DOUBLE-STRUCK SMALL V
+        {"vprop",            0x0221D},  // PROPORTIONAL TO
+        {"vrtri",            0x022B3},  // CONTAINS AS NORMAL SUBGROUP
+        {"Vscr",             0x1D4B1},  // MATHEMATICAL SCRIPT CAPITAL V
+        {"vscr",             0x1D4CB},  // MATHEMATICAL SCRIPT SMALL V
+//      "vsubne",           0x0228A;0x0FE00},  // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
+//      "vsubnE",           0x02ACB;0x0FE00},  // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
+//      "vsupne",           0x0228B;0x0FE00},  // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
+//      "vsupnE",           0x02ACC;0x0FE00},  // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
+        {"Vvdash",           0x022AA},  // TRIPLE VERTICAL BAR RIGHT TURNSTILE
+        {"vzigzag",          0x0299A},  // VERTICAL ZIGZAG LINE
+        {NULL,               0}
+};
+
+static NameId namesW[]={
+        {"Wcirc",            0x00174},  // LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+        {"wcirc",            0x00175},  // LATIN SMALL LETTER W WITH CIRCUMFLEX
+        {"wedbar",           0x02A5F},  // LOGICAL AND WITH UNDERBAR
+        {"wedge",            0x02227},  // LOGICAL AND
+        {"Wedge",            0x022C0},  // N-ARY LOGICAL AND
+        {"wedgeq",           0x02259},  // ESTIMATES
+        {"weierp",           0x02118},  // SCRIPT CAPITAL P
+        {"Wfr",              0x1D51A},  // MATHEMATICAL FRAKTUR CAPITAL W
+        {"wfr",              0x1D534},  // MATHEMATICAL FRAKTUR SMALL W
+        {"Wopf",             0x1D54E},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL W
+        {"wopf",             0x1D568},  // MATHEMATICAL DOUBLE-STRUCK SMALL W
+        {"wp",               0x02118},  // SCRIPT CAPITAL P
+        {"wr",               0x02240},  // WREATH PRODUCT
+        {"wreath",           0x02240},  // WREATH PRODUCT
+        {"Wscr",             0x1D4B2},  // MATHEMATICAL SCRIPT CAPITAL W
+        {"wscr",             0x1D4CC},  // MATHEMATICAL SCRIPT SMALL W
+        {NULL,               0}
+};
+
+static NameId namesX[]={
+        {"xcap",             0x022C2},  // N-ARY INTERSECTION
+        {"xcirc",            0x025EF},  // LARGE CIRCLE
+        {"xcup",             0x022C3},  // N-ARY UNION
+        {"xdtri",            0x025BD},  // WHITE DOWN-POINTING TRIANGLE
+        {"Xfr",              0x1D51B},  // MATHEMATICAL FRAKTUR CAPITAL X
+        {"xfr",              0x1D535},  // MATHEMATICAL FRAKTUR SMALL X
+        {"Xgr",              0x0039E},  // GREEK CAPITAL LETTER XI
+        {"xgr",              0x003BE},  // GREEK SMALL LETTER XI
+        {"xharr",            0x027F7},  // LONG LEFT RIGHT ARROW
+        {"xhArr",            0x027FA},  // LONG LEFT RIGHT DOUBLE ARROW
+        {"Xi",               0x0039E},  // GREEK CAPITAL LETTER XI
+        {"xi",               0x003BE},  // GREEK SMALL LETTER XI
+        {"xlarr",            0x027F5},  // LONG LEFTWARDS ARROW
+        {"xlArr",            0x027F8},  // LONG LEFTWARDS DOUBLE ARROW
+        {"xmap",             0x027FC},  // LONG RIGHTWARDS ARROW FROM BAR
+        {"xnis",             0x022FB},  // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+        {"xodot",            0x02A00},  // N-ARY CIRCLED DOT OPERATOR
+        {"Xopf",             0x1D54F},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL X
+        {"xopf",             0x1D569},  // MATHEMATICAL DOUBLE-STRUCK SMALL X
+        {"xoplus",           0x02A01},  // N-ARY CIRCLED PLUS OPERATOR
+        {"xotime",           0x02A02},  // N-ARY CIRCLED TIMES OPERATOR
+        {"xrarr",            0x027F6},  // LONG RIGHTWARDS ARROW
+        {"xrArr",            0x027F9},  // LONG RIGHTWARDS DOUBLE ARROW
+        {"Xscr",             0x1D4B3},  // MATHEMATICAL SCRIPT CAPITAL X
+        {"xscr",             0x1D4CD},  // MATHEMATICAL SCRIPT SMALL X
+        {"xsqcup",           0x02A06},  // N-ARY SQUARE UNION OPERATOR
+        {"xuplus",           0x02A04},  // N-ARY UNION OPERATOR WITH PLUS
+        {"xutri",            0x025B3},  // WHITE UP-POINTING TRIANGLE
+        {"xvee",             0x022C1},  // N-ARY LOGICAL OR
+        {"xwedge",           0x022C0},  // N-ARY LOGICAL AND
+        {NULL,               0}
+};
+
+static NameId namesY[]={
+        {"Yacute",           0x000DD},  // LATIN CAPITAL LETTER Y WITH ACUTE
+        {"yacute",           0x000FD},  // LATIN SMALL LETTER Y WITH ACUTE
+        {"YAcy",             0x0042F},  // CYRILLIC CAPITAL LETTER YA
+        {"yacy",             0x0044F},  // CYRILLIC SMALL LETTER YA
+        {"Ycirc",            0x00176},  // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+        {"ycirc",            0x00177},  // LATIN SMALL LETTER Y WITH CIRCUMFLEX
+        {"Ycy",              0x0042B},  // CYRILLIC CAPITAL LETTER YERU
+        {"ycy",              0x0044B},  // CYRILLIC SMALL LETTER YERU
+        {"yen",              0x000A5},  // YEN SIGN
+        {"Yfr",              0x1D51C},  // MATHEMATICAL FRAKTUR CAPITAL Y
+        {"yfr",              0x1D536},  // MATHEMATICAL FRAKTUR SMALL Y
+        {"YIcy",             0x00407},  // CYRILLIC CAPITAL LETTER YI
+        {"yicy",             0x00457},  // CYRILLIC SMALL LETTER YI
+        {"Yopf",             0x1D550},  // MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+        {"yopf",             0x1D56A},  // MATHEMATICAL DOUBLE-STRUCK SMALL Y
+        {"Yscr",             0x1D4B4},  // MATHEMATICAL SCRIPT CAPITAL Y
+        {"yscr",             0x1D4CE},  // MATHEMATICAL SCRIPT SMALL Y
+        {"YUcy",             0x0042E},  // CYRILLIC CAPITAL LETTER YU
+        {"yucy",             0x0044E},  // CYRILLIC SMALL LETTER YU
+        {"yuml",             0x000FF},  // LATIN SMALL LETTER Y WITH DIAERESIS
+        {"Yuml",             0x00178},  // LATIN CAPITAL LETTER Y WITH DIAERESIS
+        {NULL,               0}
+};
+
+static NameId namesZ[]={
+        {"Zacute",           0x00179},  // LATIN CAPITAL LETTER Z WITH ACUTE
+        {"zacute",           0x0017A},  // LATIN SMALL LETTER Z WITH ACUTE
+        {"Zcaron",           0x0017D},  // LATIN CAPITAL LETTER Z WITH CARON
+        {"zcaron",           0x0017E},  // LATIN SMALL LETTER Z WITH CARON
+        {"Zcy",              0x00417},  // CYRILLIC CAPITAL LETTER ZE
+        {"zcy",              0x00437},  // CYRILLIC SMALL LETTER ZE
+        {"Zdot",             0x0017B},  // LATIN CAPITAL LETTER Z WITH DOT ABOVE
+        {"zdot",             0x0017C},  // LATIN SMALL LETTER Z WITH DOT ABOVE
+        {"zeetrf",           0x02128},  // BLACK-LETTER CAPITAL Z
+        {"ZeroWidthSpace",   0x0200B},  // ZERO WIDTH SPACE
+        {"Zeta",             0x00396},  // GREEK CAPITAL LETTER ZETA
+        {"zeta",             0x003B6},  // GREEK SMALL LETTER ZETA
+        {"Zfr",              0x02128},  // BLACK-LETTER CAPITAL Z
+        {"zfr",              0x1D537},  // MATHEMATICAL FRAKTUR SMALL Z
+        {"Zgr",              0x00396},  // GREEK CAPITAL LETTER ZETA
+        {"zgr",              0x003B6},  // GREEK SMALL LETTER ZETA
+        {"ZHcy",             0x00416},  // CYRILLIC CAPITAL LETTER ZHE
+        {"zhcy",             0x00436},  // CYRILLIC SMALL LETTER ZHE
+        {"zigrarr",          0x021DD},  // RIGHTWARDS SQUIGGLE ARROW
+        {"Zopf",             0x02124},  // DOUBLE-STRUCK CAPITAL Z
+        {"zopf",             0x1D56B},  // MATHEMATICAL DOUBLE-STRUCK SMALL Z
+        {"Zscr",             0x1D4B5},  // MATHEMATICAL SCRIPT CAPITAL Z
+        {"zscr",             0x1D4CF},  // MATHEMATICAL SCRIPT SMALL Z
+        {"zwj",              0x0200D},  // ZERO WIDTH JOINER
+        {"zwnj",             0x0200C},  // ZERO WIDTH NON-JOINER
+        {NULL,               0}
+};
+
+// @todo@ order namesTable and names? by frequency
+static NameId* namesTable[] = {
+        namesA, namesB, namesC, namesD, namesE, namesF, namesG, namesH, namesI,
+        namesJ, namesK, namesL, namesM, namesN, namesO, namesP, namesQ, namesR,
+        namesS, namesT, namesU, namesV, namesW, namesX, namesY, namesZ, NULL
+};
+
+int HtmlNamedEntity(const utf8_t *p, size_t length)
+{
+    int tableIndex = tolower(*p) - 'a';
+    if (tableIndex >= 0 && tableIndex < 26)
+    {
+        NameId* names = namesTable[tableIndex];
+
+        for (size_t i = 0; names[i].name; i++)
+        {
+            if (strncmp(names[i].name, (char *)p, length) == 0)
+                return names[i].value;
+        }
+    }
+    return -1;
+}
+
diff --git a/gcc/d/dfrontend/enum.h b/gcc/d/dfrontend/enum.h
new file mode 100644
index 00000000000..7d6e25766da
--- /dev/null
+++ b/gcc/d/dfrontend/enum.h
@@ -0,0 +1,102 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/enum.h
+ */
+
+#ifndef DMD_ENUM_H
+#define DMD_ENUM_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "dsymbol.h"
+#include "declaration.h"
+#include "tokens.h"
+
+class Identifier;
+class Type;
+class Expression;
+class VarDeclaration;
+
+class EnumDeclaration : public ScopeDsymbol
+{
+public:
+    /* The separate, and distinct, cases are:
+     *  1. enum { ... }
+     *  2. enum : memtype { ... }
+     *  3. enum id { ... }
+     *  4. enum id : memtype { ... }
+     *  5. enum id : memtype;
+     *  6. enum id;
+     */
+    Type *type;                 // the TypeEnum
+    Type *memtype;              // type of the members
+    Prot protection;
+
+    Expression *maxval;
+    Expression *minval;
+    Expression *defaultval;     // default initializer
+
+    bool isdeprecated;
+    bool added;
+    int inuse;
+
+    EnumDeclaration(Loc loc, Identifier *id, Type *memtype);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void addMember(Scope *sc, ScopeDsymbol *sds);
+    void setScope(Scope *sc);
+    void semantic(Scope *sc);
+    bool oneMember(Dsymbol **ps, Identifier *ident);
+    Type *getType();
+    const char *kind();
+    Dsymbol *search(Loc, Identifier *ident, int flags = SearchLocalsOnly);
+    bool isDeprecated();                // is Dsymbol deprecated?
+    Prot prot();
+    Expression *getMaxMinValue(Loc loc, Identifier *id);
+    Expression *getDefaultValue(Loc loc);
+    Type *getMemtype(Loc loc);
+
+    EnumDeclaration *isEnumDeclaration() { return this; }
+
+    Symbol *sinit;
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+
+class EnumMember : public VarDeclaration
+{
+public:
+    /* Can take the following forms:
+     *  1. id
+     *  2. id = value
+     *  3. type id = value
+     */
+    Expression *&value();
+
+    // A cast() is injected to 'value' after semantic(),
+    // but 'origValue' will preserve the original value,
+    // or previous value + 1 if none was specified.
+    Expression *origValue;
+    Type *origType;
+
+    EnumDeclaration *ed;
+
+    EnumMember(Loc loc, Identifier *id, Expression *value, Type *origType);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    const char *kind();
+    void semantic(Scope *sc);
+    Expression *getVarExp(Loc loc, Scope *sc);
+
+    EnumMember *isEnumMember() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#endif /* DMD_ENUM_H */
diff --git a/gcc/d/dfrontend/errors.h b/gcc/d/dfrontend/errors.h
new file mode 100644
index 00000000000..0827ec0d976
--- /dev/null
+++ b/gcc/d/dfrontend/errors.h
@@ -0,0 +1,55 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/mars.h
+ */
+
+#ifndef DMD_ERRORS_H
+#define DMD_ERRORS_H
+
+#ifdef __DMC__
+#pragma once
+#endif
+
+#include "mars.h"
+
+bool isConsoleColorSupported();
+
+#if defined(__GNUC__)
+#define D_ATTRIBUTE_FORMAT(m, n) __attribute__((format(printf, m, n))) __attribute__((nonnull (m)))
+#else
+#define D_ATTRIBUTE_FORMAT(m, n)
+#endif
+
+// Print a warning, deprecation, or error, accepts printf-like format specifiers.
+D_ATTRIBUTE_FORMAT(2, 3) void warning(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void warningSupplemental(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void deprecation(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void deprecationSupplemental(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void error(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void errorSupplemental(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 0) void verror(const Loc& loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL, const char *header = "Error: ");
+D_ATTRIBUTE_FORMAT(2, 0) void verrorSupplemental(const Loc& loc, const char *format, va_list ap);
+D_ATTRIBUTE_FORMAT(2, 0) void vwarning(const Loc& loc, const char *format, va_list);
+D_ATTRIBUTE_FORMAT(2, 0) void vwarningSupplemental(const Loc& loc, const char *format, va_list ap);
+D_ATTRIBUTE_FORMAT(2, 0) void vdeprecation(const Loc& loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL);
+D_ATTRIBUTE_FORMAT(2, 0) void vdeprecationSupplemental(const Loc& loc, const char *format, va_list ap);
+
+#if defined(__GNUC__) || defined(__clang__)
+#define D_ATTRIBUTE_NORETURN __attribute__((noreturn))
+#elif _MSC_VER
+#define D_ATTRIBUTE_NORETURN __declspec(noreturn)
+#else
+#define D_ATTRIBUTE_NORETURN
+#endif
+
+// Called after printing out fatal error messages.
+D_ATTRIBUTE_NORETURN void fatal();
+D_ATTRIBUTE_NORETURN void halt();
+
+#endif /* DMD_ERRORS_H */
diff --git a/gcc/d/dfrontend/escape.c b/gcc/d/dfrontend/escape.c
new file mode 100644
index 00000000000..783b1e6bbf9
--- /dev/null
+++ b/gcc/d/dfrontend/escape.c
@@ -0,0 +1,1152 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2015 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/escape.c
+ */
+
+#include "init.h"
+#include "expression.h"
+#include "scope.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "module.h"
+
+/************************************
+ * Aggregate the data collected by the escapeBy??() functions.
+ */
+struct EscapeByResults
+{
+    VarDeclarations byref;      // array into which variables being returned by ref are inserted
+    VarDeclarations byvalue;    // array into which variables with values containing pointers are inserted
+    FuncDeclarations byfunc;    // nested functions that are turned into delegates
+    Expressions byexp;          // array into which temporaries being returned by ref are inserted
+};
+
+static bool checkEscapeImpl(Scope *sc, Expression *e, bool refs, bool gag);
+static void inferReturn(FuncDeclaration *fd, VarDeclaration *v);
+static void escapeByValue(Expression *e, EscapeByResults *er);
+static void escapeByRef(Expression *e, EscapeByResults *er);
+static void findAllOuterAccessedVariables(FuncDeclaration *fd, VarDeclarations *vars);
+
+/* 'v' is assigned unsafely to 'par'
+*/
+static void unsafeAssign(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag,
+                         bool &result, VarDeclaration *v, const char *desc)
+{
+    if (global.params.vsafe && sc->func->setUnsafe())
+    {
+        if (!gag)
+            error(arg->loc, "%s %s assigned to non-scope parameter %s calling %s",
+                desc, v->toChars(), par->toChars(), fdc ? fdc->toPrettyChars() : "indirectly");
+        result = true;
+    }
+}
+
+/****************************************
+ * Function parameter par is being initialized to arg,
+ * and par may escape.
+ * Detect if scoped values can escape this way.
+ * Print error messages when these are detected.
+ * Params:
+ *      sc = used to determine current function and module
+ *      par = identifier of function parameter
+ *      arg = initializer for param
+ *      gag = do not print error messages
+ * Returns:
+ *      true if pointers to the stack can escape via assignment
+ */
+bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag)
+{
+    //printf("checkParamArgumentEscape(arg: %s par: %s)\n", arg->toChars(), par->toChars());
+    //printf("type = %s, %d\n", arg->type->toChars(), arg->type->hasPointers());
+
+    if (!arg->type->hasPointers())
+        return false;
+
+    EscapeByResults er;
+
+    escapeByValue(arg, &er);
+
+    if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
+        return false;
+
+    bool result = false;
+
+    for (size_t i = 0; i < er.byvalue.dim; i++)
+    {
+        //printf("byvalue %s\n", v->toChars());
+        VarDeclaration *v = er.byvalue[i];
+        if (v->isDataseg())
+            continue;
+
+        Dsymbol *p = v->toParent2();
+
+        v->storage_class &= ~STCmaybescope;
+
+        if (v->isScope())
+        {
+            unsafeAssign(sc, fdc, par, arg, gag, result, v, "scope variable");
+        }
+        else if (v->storage_class & STCvariadic && p == sc->func)
+        {
+            Type *tb = v->type->toBasetype();
+            if (tb->ty == Tarray || tb->ty == Tsarray)
+            {
+                unsafeAssign(sc, fdc, par, arg, gag, result, v, "variadic variable");
+            }
+        }
+        else
+        {
+            /* v is not 'scope', and is assigned to a parameter that may escape.
+             * Therefore, v can never be 'scope'.
+             */
+            v->doNotInferScope = true;
+        }
+    }
+
+    for (size_t i = 0; i < er.byref.dim; i++)
+    {
+        VarDeclaration *v = er.byref[i];
+        if (v->isDataseg())
+            continue;
+
+        Dsymbol *p = v->toParent2();
+
+        v->storage_class &= ~STCmaybescope;
+
+        if ((v->storage_class & (STCref | STCout)) == 0 && p == sc->func)
+        {
+            unsafeAssign(sc, fdc, par, arg, gag, result, v, "reference to local variable");
+            continue;
+        }
+    }
+
+    for (size_t i = 0; i < er.byfunc.dim; i++)
+    {
+        FuncDeclaration *fd = er.byfunc[i];
+        //printf("fd = %s, %d\n", fd->toChars(), fd->tookAddressOf);
+        VarDeclarations vars;
+        findAllOuterAccessedVariables(fd, &vars);
+
+        for (size_t j = 0; j < vars.dim; j++)
+        {
+            VarDeclaration *v = vars[j];
+            //printf("v = %s\n", v->toChars());
+            if (v->isDataseg())
+                continue;
+
+            Dsymbol *p = v->toParent2();
+
+            v->storage_class &= ~STCmaybescope;
+
+            if ((v->storage_class & (STCref | STCout | STCscope)) && p == sc->func)
+            {
+                unsafeAssign(sc, fdc, par, arg, gag, result, v, "reference to local");
+                continue;
+            }
+        }
+    }
+
+    for (size_t i = 0; i < er.byexp.dim; i++)
+    {
+        Expression *ee = er.byexp[i];
+        if (sc->func->setUnsafe())
+        {
+            if (!gag)
+                error(ee->loc, "reference to stack allocated value returned by %s assigned to non-scope parameter %s",
+                    ee->toChars(), par->toChars());
+            result = true;
+        }
+    }
+
+    return result;
+}
+
+/****************************************
+ * Given an AssignExp, determine if the lvalue will cause
+ * the contents of the rvalue to escape.
+ * Print error messages when these are detected.
+ * Infer 'scope' for the lvalue where possible, in order
+ * to eliminate the error.
+ * Params:
+ *      sc = used to determine current function and module
+ *      ae = AssignExp to check for any pointers to the stack
+ *      gag = do not print error messages
+ * Returns:
+ *      true if pointers to the stack can escape via assignment
+ */
+bool checkAssignEscape(Scope *sc, Expression *e, bool gag)
+{
+    //printf("checkAssignEscape(e: %s)\n", e->toChars());
+    if (e->op != TOKassign && e->op != TOKblit && e->op != TOKconstruct)
+        return false;
+    AssignExp *ae = (AssignExp *)e;
+    Expression *e1 = ae->e1;
+    Expression *e2 = ae->e2;
+    //printf("type = %s, %d\n", e1->type->toChars(), e1->type->hasPointers());
+
+    if (!e1->type->hasPointers())
+        return false;
+
+    if (e1->op == TOKslice)
+        return false;
+
+    EscapeByResults er;
+
+    escapeByValue(e2, &er);
+
+    if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
+        return false;
+
+    VarDeclaration *va = NULL;
+    while (e1->op == TOKdotvar)
+        e1 = ((DotVarExp *)e1)->e1;
+
+    if (e1->op == TOKvar)
+        va = ((VarExp *)e1)->var->isVarDeclaration();
+    else if (e1->op == TOKthis)
+        va = ((ThisExp *)e1)->var->isVarDeclaration();
+    else if (e1->op == TOKindex)
+    {
+        IndexExp *ie = (IndexExp *)e1;
+        if (ie->e1->op == TOKvar && ie->e1->type->toBasetype()->ty == Tsarray)
+            va = ((VarExp *)ie->e1)->var->isVarDeclaration();
+    }
+
+    // Try to infer 'scope' for va if in a function not marked @system
+    bool inferScope = false;
+    if (va && sc->func && sc->func->type && sc->func->type->ty == Tfunction)
+        inferScope = ((TypeFunction *)sc->func->type)->trust != TRUSTsystem;
+
+    bool result = false;
+    for (size_t i = 0; i < er.byvalue.dim; i++)
+    {
+        VarDeclaration *v = er.byvalue[i];
+        //printf("byvalue: %s\n", v->toChars());
+        if (v->isDataseg())
+            continue;
+
+        Dsymbol *p = v->toParent2();
+
+        if (!(va && va->isScope()))
+            v->storage_class &= ~STCmaybescope;
+
+        if (v->isScope())
+        {
+            // If va's lifetime encloses v's, then error
+            if (va && va->enclosesLifetimeOf(v) && !(v->storage_class & STCparameter) && sc->func->setUnsafe())
+            {
+                if (!gag)
+                    error(ae->loc, "scope variable %s assigned to %s with longer lifetime", v->toChars(), va->toChars());
+                result = true;
+                continue;
+            }
+
+            if (va && !va->isDataseg() && !va->doNotInferScope)
+            {
+                if (!va->isScope() && inferScope)
+                {   //printf("inferring scope for %s\n", va->toChars());
+                    va->storage_class |= STCscope | STCscopeinferred;
+                }
+                continue;
+            }
+            if (sc->func->setUnsafe())
+            {
+                if (!gag)
+                    error(ae->loc, "scope variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
+                result = true;
+            }
+        }
+        else if (v->storage_class & STCvariadic && p == sc->func)
+        {
+            Type *tb = v->type->toBasetype();
+            if (tb->ty == Tarray || tb->ty == Tsarray)
+            {
+                if (va && !va->isDataseg() && !va->doNotInferScope)
+                {
+                    if (!va->isScope() && inferScope)
+                    {   //printf("inferring scope for %s\n", va->toChars());
+                        va->storage_class |= STCscope | STCscopeinferred;
+                    }
+                    continue;
+                }
+                if (sc->func->setUnsafe())
+                {
+                    if (!gag)
+                        error(ae->loc, "variadic variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
+                    result = true;
+                }
+            }
+        }
+        else
+        {
+            /* v is not 'scope', and we didn't check the scope of where we assigned it to.
+             * It may escape via that assignment, therefore, v can never be 'scope'.
+             */
+            v->doNotInferScope = true;
+        }
+    }
+
+    for (size_t i = 0; i < er.byref.dim; i++)
+    {
+        VarDeclaration *v = er.byref[i];
+        //printf("byref: %s\n", v->toChars());
+        if (v->isDataseg())
+            continue;
+
+        Dsymbol *p = v->toParent2();
+
+        // If va's lifetime encloses v's, then error
+        if (va && va->enclosesLifetimeOf(v) && !(v->storage_class & STCparameter) && sc->func->setUnsafe())
+        {
+            if (!gag)
+                error(ae->loc, "address of variable %s assigned to %s with longer lifetime", v->toChars(), va->toChars());
+            result = true;
+            continue;
+        }
+
+        if (!(va && va->isScope()))
+            v->storage_class &= ~STCmaybescope;
+
+        if ((v->storage_class & (STCref | STCout)) == 0 && p == sc->func)
+        {
+            if (va && !va->isDataseg() && !va->doNotInferScope)
+            {
+                if (!va->isScope() && inferScope &&
+                    va->type->toBasetype()->ty != Tclass)  // scope classes are special
+                {   //printf("inferring scope for %s\n", va->toChars());
+                    va->storage_class |= STCscope | STCscopeinferred;
+                }
+                continue;
+            }
+            if (sc->func->setUnsafe())
+            {
+                if (!gag)
+                    error(ae->loc, "reference to local variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
+                result = true;
+            }
+            continue;
+        }
+    }
+
+    for (size_t i = 0; i < er.byfunc.dim; i++)
+    {
+        FuncDeclaration *fd = er.byfunc[i];
+        //printf("fd = %s, %d\n", fd->toChars(), fd->tookAddressOf);
+        VarDeclarations vars;
+        findAllOuterAccessedVariables(fd, &vars);
+
+        for (size_t j = 0; j < vars.dim; j++)
+        {
+            VarDeclaration *v = vars[j];
+            //printf("v = %s\n", v->toChars());
+            if (v->isDataseg())
+                continue;
+
+            Dsymbol *p = v->toParent2();
+
+            if (!(va && va->isScope()))
+                v->storage_class &= ~STCmaybescope;
+
+            if ((v->storage_class & (STCref | STCout | STCscope)) && p == sc->func)
+            {
+                if (va && !va->isDataseg() && !va->doNotInferScope)
+                {
+                    /* Don't infer STCscope for va, because then a closure
+                     * won't be generated for sc->func.
+                     */
+                    //if (!va->isScope() && inferScope)
+                        //va->storage_class |= STCscope | STCscopeinferred;
+                    continue;
+                }
+                if (sc->func->setUnsafe())
+                {
+                    if (!gag)
+                        error(ae->loc, "reference to local %s assigned to non-scope %s in @safe code", v->toChars(), e1->toChars());
+                    result = true;
+                }
+                continue;
+            }
+        }
+    }
+
+    for (size_t i = 0; i < er.byexp.dim; i++)
+    {
+        Expression *ee = er.byexp[i];
+        if (va && !va->isDataseg() && !va->doNotInferScope)
+        {
+            if (!va->isScope() && inferScope)
+            {   //printf("inferring scope for %s\n", va->toChars());
+                va->storage_class |= STCscope | STCscopeinferred;
+            }
+            continue;
+        }
+        if (sc->func->setUnsafe())
+        {
+            if (!gag)
+                error(ee->loc, "reference to stack allocated value returned by %s assigned to non-scope %s",
+                    ee->toChars(), e1->toChars());
+            result = true;
+        }
+    }
+
+    return result;
+}
+
+/************************************
+ * Detect cases where pointers to the stack can 'escape' the
+ * lifetime of the stack frame.
+ * Params:
+ *      sc = used to determine current function and module
+ *      e = expression to check for any pointers to the stack
+ *      gag = do not print error messages
+ * Returns:
+ *      true if pointers to the stack can escape
+ */
+
+bool checkEscape(Scope *sc, Expression *e, bool gag)
+{
+    //printf("[%s] checkEscape, e = %s\n", e->loc->toChars(), e->toChars());
+    return checkEscapeImpl(sc, e, false, gag);
+}
+
+/************************************
+ * Detect cases where returning 'e' by ref can result in a reference to the stack
+ * being returned.
+ * Print error messages when these are detected.
+ * Params:
+ *      sc = used to determine current function and module
+ *      e = expression to check
+ *      gag = do not print error messages
+ * Returns:
+ *      true if references to the stack can escape
+ */
+bool checkEscapeRef(Scope *sc, Expression *e, bool gag)
+{
+    //printf("[%s] checkEscapeRef, e = %s\n", e->loc.toChars(), e->toChars());
+    //printf("current function %s\n", sc->func->toChars());
+    //printf("parent2 function %s\n", sc->func->toParent2()->toChars());
+
+    return checkEscapeImpl(sc, e, true, gag);
+}
+
+static bool checkEscapeImpl(Scope *sc, Expression *e, bool refs, bool gag)
+{
+    //printf("[%s] checkEscapeImpl, e = %s\n", e->loc->toChars(), e->toChars());
+    EscapeByResults er;
+
+    if (refs)
+        escapeByRef(e, &er);
+    else
+        escapeByValue(e, &er);
+
+    if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim)
+        return false;
+
+    bool result = false;
+    for (size_t i = 0; i < er.byvalue.dim; i++)
+    {
+        VarDeclaration *v = er.byvalue[i];
+        //printf("byvalue %s\n", v->toChars());
+        if (v->isDataseg())
+            continue;
+
+        Dsymbol *p = v->toParent2();
+
+        if ((v->isScope() || (v->storage_class & STCmaybescope)) &&
+            !(v->storage_class & STCreturn) &&
+            v->isParameter() &&
+            sc->func->flags & FUNCFLAGreturnInprocess &&
+            p == sc->func)
+        {
+            inferReturn(sc->func, v);        // infer addition of 'return'
+            continue;
+        }
+
+        if (v->isScope())
+        {
+            if (v->storage_class & STCreturn)
+                continue;
+
+            if (sc->_module && sc->_module->isRoot() &&
+                /* This case comes up when the ReturnStatement of a __foreachbody is
+                 * checked for escapes by the caller of __foreachbody. Skip it.
+                 *
+                 * struct S { static int opApply(int delegate(S*) dg); }
+                 * S* foo() {
+                 *    foreach (S* s; S) // create __foreachbody for body of foreach
+                 *        return s;     // s is inferred as 'scope' but incorrectly tested in foo()
+                 *    return null; }
+                 */
+                !(!refs && p->parent == sc->func))
+            {
+                // Only look for errors if in module listed on command line
+                if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029
+                {
+                    if (!gag)
+                        error(e->loc, "scope variable %s may not be returned", v->toChars());
+                    result = true;
+                }
+                continue;
+            }
+        }
+        else if (v->storage_class & STCvariadic && p == sc->func)
+        {
+            Type *tb = v->type->toBasetype();
+            if (tb->ty == Tarray || tb->ty == Tsarray)
+            {
+                if (!gag)
+                    error(e->loc, "escaping reference to variadic parameter %s", v->toChars());
+                result = false;
+            }
+        }
+        else
+        {
+            //printf("no infer for %s\n", v->toChars());
+            v->doNotInferScope = true;
+        }
+    }
+
+    for (size_t i = 0; i < er.byref.dim; i++)
+    {
+        VarDeclaration *v = er.byref[i];
+        //printf("byref %s\n", v->toChars());
+        if (v->isDataseg())
+            continue;
+
+        Dsymbol *p = v->toParent2();
+
+        if ((v->storage_class & (STCref | STCout)) == 0)
+        {
+            if (p == sc->func)
+            {
+                if (!gag)
+                    error(e->loc, "escaping reference to local variable %s", v->toChars());
+                result = true;
+                continue;
+            }
+            FuncDeclaration *fd = p->isFuncDeclaration();
+            if (fd && sc->func->flags & FUNCFLAGreturnInprocess)
+            {
+                /* Code like:
+                 *   int x;
+                 *   auto dg = () { return &x; }
+                 * Making it:
+                 *   auto dg = () return { return &x; }
+                 * Because dg.ptr points to x, this is returning dt.ptr+offset
+                 */
+                if (global.params.vsafe)
+                    sc->func->storage_class |= STCreturn;
+            }
+        }
+
+        /* Check for returning a ref variable by 'ref', but should be 'return ref'
+         * Infer the addition of 'return', or set result to be the offending expression.
+         */
+        if ( (v->storage_class & (STCref | STCout)) &&
+             !(v->storage_class & (STCreturn | STCforeach)))
+        {
+            if ((sc->func->flags & FUNCFLAGreturnInprocess) && p == sc->func)
+            {
+                inferReturn(sc->func, v);        // infer addition of 'return'
+            }
+            else if (global.params.useDIP25 &&
+                     sc->_module && sc->_module->isRoot())
+            {
+                // Only look for errors if in module listed on command line
+
+                if (p == sc->func)
+                {
+                    //printf("escaping reference to local ref variable %s\n", v->toChars());
+                    //printf("storage class = x%llx\n", v->storage_class);
+                    if (!gag)
+                        error(e->loc, "escaping reference to local variable %s", v->toChars());
+                    result = true;
+                    continue;
+                }
+                // Don't need to be concerned if v's parent does not return a ref
+                FuncDeclaration *fd = p->isFuncDeclaration();
+                if (fd && fd->type && fd->type->ty == Tfunction)
+                {
+                    TypeFunction *tf = (TypeFunction *)fd->type;
+                    if (tf->isref)
+                    {
+                        if (!gag)
+                            error(e->loc, "escaping reference to outer local variable %s", v->toChars());
+                        result = true;
+                        continue;
+                    }
+                }
+            }
+        }
+    }
+
+    for (size_t i = 0; i < er.byexp.dim; i++)
+    {
+        Expression *ee = er.byexp[i];
+        //printf("byexp %s\n", ee->toChars());
+        if (!gag)
+            error(ee->loc, "escaping reference to stack allocated value returned by %s", ee->toChars());
+        result = true;
+    }
+
+    return result;
+}
+
+
+/*************************************
+ * Variable v needs to have 'return' inferred for it.
+ * Params:
+ *      fd = function that v is a parameter to
+ *      v = parameter that needs to be STCreturn
+ */
+
+static void inferReturn(FuncDeclaration *fd, VarDeclaration *v)
+{
+    // v is a local in the current function
+
+    //printf("for function '%s' inferring 'return' for variable '%s'\n", fd->toChars(), v->toChars());
+    v->storage_class |= STCreturn;
+
+    TypeFunction *tf = (TypeFunction *)fd->type;
+    if (v == fd->vthis)
+    {
+        /* v is the 'this' reference, so mark the function
+         */
+        fd->storage_class |= STCreturn;
+        if (tf->ty == Tfunction)
+        {
+            //printf("'this' too %p %s\n", tf, sc->func->toChars());
+            tf->isreturn = true;
+        }
+    }
+    else
+    {
+        // Perform 'return' inference on parameter
+        if (tf->ty == Tfunction && tf->parameters)
+        {
+            const size_t dim = Parameter::dim(tf->parameters);
+            for (size_t i = 0; i < dim; i++)
+            {
+                Parameter *p = Parameter::getNth(tf->parameters, i);
+                if (p->ident == v->ident)
+                {
+                    p->storageClass |= STCreturn;
+                    break;              // there can be only one
+                }
+            }
+        }
+    }
+}
+
+
+/****************************************
+ * e is an expression to be returned by value, and that value contains pointers.
+ * Walk e to determine which variables are possibly being
+ * returned by value, such as:
+ *      int* function(int* p) { return p; }
+ * If e is a form of &p, determine which variables have content
+ * which is being returned as ref, such as:
+ *      int* function(int i) { return &i; }
+ * Multiple variables can be inserted, because of expressions like this:
+ *      int function(bool b, int i, int* p) { return b ? &i : p; }
+ *
+ * No side effects.
+ *
+ * Params:
+ *      e = expression to be returned by value
+ *      er = where to place collected data
+ */
+static void escapeByValue(Expression *e, EscapeByResults *er)
+{
+    //printf("[%s] escapeByValue, e: %s\n", e->loc.toChars(), e->toChars());
+
+    class EscapeVisitor : public Visitor
+    {
+    public:
+        EscapeByResults *er;
+
+        EscapeVisitor(EscapeByResults *er)
+            : er(er)
+        {
+        }
+
+        void visit(Expression *e)
+        {
+        }
+
+        void visit(AddrExp *e)
+        {
+            escapeByRef(e->e1, er);
+        }
+
+        void visit(SymOffExp *e)
+        {
+            VarDeclaration *v = e->var->isVarDeclaration();
+            if (v)
+                er->byref.push(v);
+        }
+
+        void visit(VarExp *e)
+        {
+            VarDeclaration *v = e->var->isVarDeclaration();
+            if (v)
+                er->byvalue.push(v);
+        }
+
+        void visit(ThisExp *e)
+        {
+            if (e->var)
+                er->byvalue.push(e->var);
+        }
+
+        void visit(DotVarExp *e)
+        {
+            Type *t = e->e1->type->toBasetype();
+            if (t->ty == Tstruct)
+                e->e1->accept(this);
+        }
+
+        void visit(DelegateExp *e)
+        {
+            er->byfunc.push(e->func);
+        }
+
+        void visit(FuncExp *e)
+        {
+            if (e->fd->tok == TOKdelegate)
+                er->byfunc.push(e->fd);
+        }
+
+        void visit(TupleExp *e)
+        {
+            if (e->exps->dim)
+            {
+                (*e->exps)[e->exps->dim - 1]->accept(this); // last one only
+            }
+        }
+
+        void visit(ArrayLiteralExp *e)
+        {
+            Type *tb = e->type->toBasetype();
+            if (tb->ty == Tsarray || tb->ty == Tarray)
+            {
+                if (e->basis)
+                    e->basis->accept(this);
+                for (size_t i = 0; i < e->elements->dim; i++)
+                {
+                    Expression *el = (*e->elements)[i];
+                    if (el)
+                        el->accept(this);
+                }
+            }
+        }
+
+        void visit(StructLiteralExp *e)
+        {
+            if (e->elements)
+            {
+                for (size_t i = 0; i < e->elements->dim; i++)
+                {
+                    Expression *ex = (*e->elements)[i];
+                    if (ex)
+                        ex->accept(this);
+                }
+            }
+        }
+
+        void visit(NewExp *e)
+        {
+            Type *tb = e->newtype->toBasetype();
+            if (tb->ty == Tstruct && !e->member && e->arguments)
+            {
+                for (size_t i = 0; i < e->arguments->dim; i++)
+                {
+                    Expression *ex = (*e->arguments)[i];
+                    if (ex)
+                        ex->accept(this);
+                }
+            }
+        }
+
+        void visit(CastExp *e)
+        {
+            Type *tb = e->type->toBasetype();
+            if (tb->ty == Tarray &&
+                e->e1->type->toBasetype()->ty == Tsarray)
+            {
+                escapeByRef(e->e1, er);
+            }
+            else
+                e->e1->accept(this);
+        }
+
+        void visit(SliceExp *e)
+        {
+            if (e->e1->op == TOKvar)
+            {
+                VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
+                Type *tb = e->type->toBasetype();
+                if (v)
+                {
+                    if (tb->ty == Tsarray)
+                        return;
+                    if (v->storage_class & STCvariadic)
+                    {
+                        er->byvalue.push(v);
+                        return;
+                    }
+                }
+            }
+            Type *t1b = e->e1->type->toBasetype();
+            if (t1b->ty == Tsarray)
+            {
+                Type *tb = e->type->toBasetype();
+                if (tb->ty != Tsarray)
+                    escapeByRef(e->e1, er);
+            }
+            else
+                e->e1->accept(this);
+        }
+
+        void visit(BinExp *e)
+        {
+            Type *tb = e->type->toBasetype();
+            if (tb->ty == Tpointer)
+            {
+                e->e1->accept(this);
+                e->e2->accept(this);
+            }
+        }
+
+        void visit(BinAssignExp *e)
+        {
+            e->e1->accept(this);
+        }
+
+        void visit(AssignExp *e)
+        {
+            e->e1->accept(this);
+        }
+
+        void visit(CommaExp *e)
+        {
+            e->e2->accept(this);
+        }
+
+        void visit(CondExp *e)
+        {
+            e->e1->accept(this);
+            e->e2->accept(this);
+        }
+
+        void visit(CallExp *e)
+        {
+            //printf("CallExp(): %s\n", e->toChars());
+            /* Check each argument that is
+             * passed as 'return scope'.
+             */
+            Type *t1 = e->e1->type->toBasetype();
+            TypeFunction *tf = NULL;
+            TypeDelegate *dg = NULL;
+            if (t1->ty == Tdelegate)
+            {
+                dg = (TypeDelegate *)t1;
+                tf = (TypeFunction *)dg->next;
+            }
+            else if (t1->ty == Tfunction)
+                tf = (TypeFunction *)t1;
+            else
+                return;
+
+            if (e->arguments && e->arguments->dim)
+            {
+                /* j=1 if _arguments[] is first argument,
+                 * skip it because it is not passed by ref
+                 */
+                int j = (tf->linkage == LINKd && tf->varargs == 1);
+                for (size_t i = j; i < e->arguments->dim; ++i)
+                {
+                    Expression *arg = (*e->arguments)[i];
+                    size_t nparams = Parameter::dim(tf->parameters);
+                    if (i - j < nparams && i >= j)
+                    {
+                        Parameter *p = Parameter::getNth(tf->parameters, i - j);
+                        const StorageClass stc = tf->parameterStorageClass(p);
+                        if ((stc & (STCscope)) && (stc & STCreturn))
+                            arg->accept(this);
+                        else if ((stc & (STCref)) && (stc & STCreturn))
+                            escapeByRef(arg, er);
+                    }
+                }
+            }
+            // If 'this' is returned, check it too
+            if (e->e1->op == TOKdotvar && t1->ty == Tfunction)
+            {
+                DotVarExp *dve = (DotVarExp *)e->e1;
+                FuncDeclaration *fd = dve->var->isFuncDeclaration();
+                AggregateDeclaration *ad = NULL;
+                if (global.params.vsafe && tf->isreturn && fd && (ad = fd->isThis()) != NULL)
+                {
+                    if (ad->isClassDeclaration() || tf->isscope)       // this is 'return scope'
+                        dve->e1->accept(this);
+                    else if (ad->isStructDeclaration()) // this is 'return ref'
+                        escapeByRef(dve->e1, er);
+                }
+                else if (dve->var->storage_class & STCreturn || tf->isreturn)
+                {
+                    if (dve->var->storage_class & STCscope)
+                        dve->e1->accept(this);
+                    else if (dve->var->storage_class & STCref)
+                        escapeByRef(dve->e1, er);
+                }
+            }
+
+            /* If returning the result of a delegate call, the .ptr
+             * field of the delegate must be checked.
+             */
+            if (dg)
+            {
+                if (tf->isreturn)
+                    e->e1->accept(this);
+            }
+        }
+    };
+
+    EscapeVisitor v(er);
+    e->accept(&v);
+}
+
+/****************************************
+ * e is an expression to be returned by 'ref'.
+ * Walk e to determine which variables are possibly being
+ * returned by ref, such as:
+ *      ref int function(int i) { return i; }
+ * If e is a form of *p, determine which variables have content
+ * which is being returned as ref, such as:
+ *      ref int function(int* p) { return *p; }
+ * Multiple variables can be inserted, because of expressions like this:
+ *      ref int function(bool b, int i, int* p) { return b ? i : *p; }
+ *
+ * No side effects.
+ *
+ * Params:
+ *      e = expression to be returned by 'ref'
+ *      er = where to place collected data
+ */
+static void escapeByRef(Expression *e, EscapeByResults *er)
+{
+    //printf("[%s] escapeByRef, e: %s\n", e->loc->toChars(), e->toChars());
+    class EscapeRefVisitor : public Visitor
+    {
+    public:
+        EscapeByResults *er;
+
+        EscapeRefVisitor(EscapeByResults *er)
+            : er(er)
+        {
+        }
+
+        void visit(Expression *e)
+        {
+        }
+
+        void visit(VarExp *e)
+        {
+            VarDeclaration *v = e->var->isVarDeclaration();
+            if (v)
+            {
+                if (v->storage_class & STCref && v->storage_class & (STCforeach | STCtemp) && v->_init)
+                {
+                    /* If compiler generated ref temporary
+                     *   (ref v = ex; ex)
+                     * look at the initializer instead
+                     */
+                    if (ExpInitializer *ez = v->_init->isExpInitializer())
+                    {
+                        assert(ez->exp && ez->exp->op == TOKconstruct);
+                        Expression *ex = ((ConstructExp *)ez->exp)->e2;
+                        ex->accept(this);
+                    }
+                }
+                else
+                    er->byref.push(v);
+            }
+        }
+
+        void visit(ThisExp *e)
+        {
+            if (e->var)
+                er->byref.push(e->var);
+        }
+
+        void visit(PtrExp *e)
+        {
+            escapeByValue(e->e1, er);
+        }
+
+        void visit(IndexExp *e)
+        {
+            Type *tb = e->e1->type->toBasetype();
+            if (e->e1->op == TOKvar)
+            {
+                VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
+                if (tb->ty == Tarray || tb->ty == Tsarray)
+                {
+                    if (v->storage_class & STCvariadic)
+                    {
+                        er->byref.push(v);
+                        return;
+                    }
+                }
+            }
+            if (tb->ty == Tsarray)
+            {
+                e->e1->accept(this);
+            }
+            else if (tb->ty == Tarray)
+            {
+                escapeByValue(e->e1, er);
+            }
+        }
+
+        void visit(DotVarExp *e)
+        {
+            Type *t1b = e->e1->type->toBasetype();
+            if (t1b->ty == Tclass)
+                escapeByValue(e->e1, er);
+            else
+                e->e1->accept(this);
+        }
+
+        void visit(BinAssignExp *e)
+        {
+            e->e1->accept(this);
+        }
+
+        void visit(AssignExp *e)
+        {
+            e->e1->accept(this);
+        }
+
+        void visit(CommaExp *e)
+        {
+            e->e2->accept(this);
+        }
+
+        void visit(CondExp *e)
+        {
+            e->e1->accept(this);
+            e->e2->accept(this);
+        }
+
+        void visit(CallExp *e)
+        {
+            /* If the function returns by ref, check each argument that is
+             * passed as 'return ref'.
+             */
+            Type *t1 = e->e1->type->toBasetype();
+            TypeFunction *tf;
+            if (t1->ty == Tdelegate)
+                tf = (TypeFunction *)((TypeDelegate *)t1)->next;
+            else if (t1->ty == Tfunction)
+                tf = (TypeFunction *)t1;
+            else
+                return;
+            if (tf->isref)
+            {
+                if (e->arguments && e->arguments->dim)
+                {
+                    /* j=1 if _arguments[] is first argument,
+                     * skip it because it is not passed by ref
+                     */
+                    int j = (tf->linkage == LINKd && tf->varargs == 1);
+
+                    for (size_t i = j; i < e->arguments->dim; ++i)
+                    {
+                        Expression *arg = (*e->arguments)[i];
+                        size_t nparams = Parameter::dim(tf->parameters);
+                        if (i - j < nparams && i >= j)
+                        {
+                            Parameter *p = Parameter::getNth(tf->parameters, i - j);
+                            const StorageClass stc = tf->parameterStorageClass(p);
+                            if ((stc & (STCout | STCref)) && (stc & STCreturn))
+                                arg->accept(this);
+                            else if ((stc & STCscope) && (stc & STCreturn))
+                            {
+                                if (arg->op == TOKdelegate)
+                                {
+                                    DelegateExp *de = (DelegateExp *)arg;
+                                    if (de->func->isNested())
+                                        er->byexp.push(de);
+                                }
+                                else
+                                    escapeByValue(arg, er);
+                            }
+                        }
+                    }
+                }
+
+                // If 'this' is returned by ref, check it too
+                if (e->e1->op == TOKdotvar && t1->ty == Tfunction)
+                {
+                    DotVarExp *dve = (DotVarExp *)e->e1;
+                    if (dve->var->storage_class & STCreturn || tf->isreturn)
+                    {
+                        if ((dve->var->storage_class & STCscope) || tf->isscope)
+                            escapeByValue(dve->e1, er);
+                        else if ((dve->var->storage_class & STCref) || tf->isref)
+                            dve->e1->accept(this);
+                    }
+
+                }
+                // If it's a delegate, check it too
+                if (e->e1->op == TOKvar && t1->ty == Tdelegate)
+                {
+                    escapeByValue(e->e1, er);
+                }
+            }
+            else
+                er->byexp.push(e);
+        }
+    };
+
+    EscapeRefVisitor v(er);
+    e->accept(&v);
+}
+
+/*************************
+ * Find all variables accessed by this delegate that are
+ * in functions enclosing it.
+ * Params:
+ *      fd = function
+ *      vars = array to append found variables to
+ */
+void findAllOuterAccessedVariables(FuncDeclaration *fd, VarDeclarations *vars)
+{
+    for (Dsymbol *p = fd->parent; p; p = p->parent)
+    {
+        FuncDeclaration *fdp = p->isFuncDeclaration();
+        if (fdp)
+        {
+            for (size_t i = 0; i < fdp->closureVars.dim; i++)
+            {
+                VarDeclaration *v = fdp->closureVars[i];
+                for (size_t j = 0; j < v->nestedrefs.dim; j++)
+                {
+                    FuncDeclaration *fdv = v->nestedrefs[j];
+                    if (fdv == fd)
+                    {
+                        //printf("accessed: %s, type %s\n", v->toChars(), v->type->toChars());
+                        vars->push(v);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/gcc/d/dfrontend/expression.c b/gcc/d/dfrontend/expression.c
new file mode 100644
index 00000000000..0c2b6dc5016
--- /dev/null
+++ b/gcc/d/dfrontend/expression.c
@@ -0,0 +1,7009 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2015 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/expression.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+#include <assert.h>
+
+#include "rmem.h"
+#include "root.h"
+
+#include "mtype.h"
+#include "init.h"
+#include "expression.h"
+#include "template.h"
+#include "utf.h"
+#include "enum.h"
+#include "scope.h"
+#include "statement.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "import.h"
+#include "id.h"
+#include "dsymbol.h"
+#include "module.h"
+#include "attrib.h"
+#include "hdrgen.h"
+#include "parse.h"
+#include "doc.h"
+#include "aav.h"
+#include "nspace.h"
+#include "ctfe.h"
+#include "target.h"
+
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag);
+bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember);
+VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
+Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
+char *MODtoChars(MOD mod);
+bool MODimplicitConv(MOD modfrom, MOD modto);
+MOD MODmerge(MOD mod1, MOD mod2);
+Expression *trySemantic(Expression *e, Scope *sc);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *semanticX(DotIdExp *exp, Scope *sc);
+Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
+Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
+
+#define LOGSEMANTIC     0
+
+/*************************************************************
+ * Given var, we need to get the
+ * right 'this' pointer if var is in an outer class, but our
+ * existing 'this' pointer is in an inner class.
+ * Input:
+ *      e1      existing 'this'
+ *      ad      struct or class we need the correct 'this' for
+ *      var     the specific member of ad we're accessing
+ */
+
+Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad,
+        Expression *e1, Declaration *var, int flag = 0)
+{
+    //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars());
+ L1:
+    Type *t = e1->type->toBasetype();
+    //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars());
+
+    /* If e1 is not the 'this' pointer for ad
+     */
+    if (ad &&
+        !(t->ty == Tpointer && t->nextOf()->ty == Tstruct &&
+          ((TypeStruct *)t->nextOf())->sym == ad)
+        &&
+        !(t->ty == Tstruct &&
+          ((TypeStruct *)t)->sym == ad)
+       )
+    {
+        ClassDeclaration *cd = ad->isClassDeclaration();
+        ClassDeclaration *tcd = t->isClassHandle();
+
+        /* e1 is the right this if ad is a base class of e1
+         */
+        if (!cd || !tcd ||
+            !(tcd == cd || cd->isBaseOf(tcd, NULL))
+           )
+        {
+            /* Only classes can be inner classes with an 'outer'
+             * member pointing to the enclosing class instance
+             */
+            if (tcd && tcd->isNested())
+            {
+                /* e1 is the 'this' pointer for an inner class: tcd.
+                 * Rewrite it as the 'this' pointer for the outer class.
+                 */
+
+                e1 = new DotVarExp(loc, e1, tcd->vthis);
+                e1->type = tcd->vthis->type;
+                e1->type = e1->type->addMod(t->mod);
+                // Do not call checkNestedRef()
+                //e1 = semantic(e1, sc);
+
+                // Skip up over nested functions, and get the enclosing
+                // class type.
+                int n = 0;
+                Dsymbol *s;
+                for (s = tcd->toParent();
+                     s && s->isFuncDeclaration();
+                     s = s->toParent())
+                {
+                    FuncDeclaration *f = s->isFuncDeclaration();
+                    if (f->vthis)
+                    {
+                        //printf("rewriting e1 to %s's this\n", f->toChars());
+                        n++;
+                        e1 = new VarExp(loc, f->vthis);
+                    }
+                    else
+                    {
+                        e1->error("need 'this' of type %s to access member %s"
+                                  " from static function %s",
+                            ad->toChars(), var->toChars(), f->toChars());
+                        e1 = new ErrorExp();
+                        return e1;
+                    }
+                }
+                if (s && s->isClassDeclaration())
+                {
+                    e1->type = s->isClassDeclaration()->type;
+                    e1->type = e1->type->addMod(t->mod);
+                    if (n > 1)
+                        e1 = semantic(e1, sc);
+                }
+                else
+                    e1 = semantic(e1, sc);
+                goto L1;
+            }
+
+            /* Can't find a path from e1 to ad
+             */
+            if (flag)
+                return NULL;
+            e1->error("this for %s needs to be type %s not type %s",
+                var->toChars(), ad->toChars(), t->toChars());
+            return new ErrorExp();
+        }
+    }
+    return e1;
+}
+
+/*****************************************
+ * Determine if 'this' is available.
+ * If it is, return the FuncDeclaration that has it.
+ */
+
+FuncDeclaration *hasThis(Scope *sc)
+{
+    //printf("hasThis()\n");
+    Dsymbol *p = sc->parent;
+    while (p && p->isTemplateMixin())
+        p = p->parent;
+    FuncDeclaration *fdthis = p ? p->isFuncDeclaration() : NULL;
+    //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : "");
+
+    // Go upwards until we find the enclosing member function
+    FuncDeclaration *fd = fdthis;
+    while (1)
+    {
+        if (!fd)
+        {
+            goto Lno;
+        }
+        if (!fd->isNested())
+            break;
+
+        Dsymbol *parent = fd->parent;
+        while (1)
+        {
+            if (!parent)
+                goto Lno;
+            TemplateInstance *ti = parent->isTemplateInstance();
+            if (ti)
+                parent = ti->parent;
+            else
+                break;
+        }
+        fd = parent->isFuncDeclaration();
+    }
+
+    if (!fd->isThis())
+    {   //printf("test '%s'\n", fd->toChars());
+        goto Lno;
+    }
+
+    assert(fd->vthis);
+    return fd;
+
+Lno:
+    return NULL;                // don't have 'this' available
+}
+
+bool isNeedThisScope(Scope *sc, Declaration *d)
+{
+    if (sc->intypeof == 1)
+        return false;
+
+    AggregateDeclaration *ad = d->isThis();
+    if (!ad)
+        return false;
+    //printf("d = %s, ad = %s\n", d->toChars(), ad->toChars());
+
+    for (Dsymbol *s = sc->parent; s; s = s->toParent2())
+    {
+        //printf("\ts = %s %s, toParent2() = %p\n", s->kind(), s->toChars(), s->toParent2());
+        if (AggregateDeclaration *ad2 = s->isAggregateDeclaration())
+        {
+            if (ad2 == ad)
+                return false;
+            else if (ad2->isNested())
+                continue;
+            else
+                return true;
+        }
+        if (FuncDeclaration *f = s->isFuncDeclaration())
+        {
+            if (f->isMember2())
+                break;
+        }
+    }
+    return true;
+}
+
+/***************************************
+ * Pull out any properties.
+ */
+
+Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL)
+{
+    //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token::toChars(e1->op), e1->toChars(), e2 ? e2->toChars() : NULL);
+    Loc loc = e1->loc;
+
+    OverloadSet *os;
+    Dsymbol *s;
+    Objects *tiargs;
+    Type *tthis;
+    if (e1->op == TOKdot)
+    {
+        DotExp *de = (DotExp *)e1;
+        if (de->e2->op == TOKoverloadset)
+        {
+            tiargs = NULL;
+            tthis  = de->e1->type;
+            os = ((OverExp *)de->e2)->vars;
+            goto Los;
+        }
+    }
+    else if (e1->op == TOKoverloadset)
+    {
+        tiargs = NULL;
+        tthis  = NULL;
+        os = ((OverExp *)e1)->vars;
+    Los:
+        assert(os);
+        FuncDeclaration *fd = NULL;
+        if (e2)
+        {
+            e2 = semantic(e2, sc);
+            if (e2->op == TOKerror)
+                return new ErrorExp();
+            e2 = resolveProperties(sc, e2);
+
+            Expressions a;
+            a.push(e2);
+
+            for (size_t i = 0; i < os->a.dim; i++)
+            {
+                FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, &a, 1);
+                if (f)
+                {
+                    if (f->errors)
+                        return new ErrorExp();
+                    fd = f;
+                    assert(fd->type->ty == Tfunction);
+                    TypeFunction *tf = (TypeFunction *)fd->type;
+                }
+            }
+            if (fd)
+            {
+                Expression *e = new CallExp(loc, e1, e2);
+                return semantic(e, sc);
+            }
+        }
+        {
+            for (size_t i = 0; i < os->a.dim; i++)
+            {
+                FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, NULL, 1);
+                if (f)
+                {
+                    if (f->errors)
+                        return new ErrorExp();
+                    fd = f;
+                    assert(fd->type->ty == Tfunction);
+                    TypeFunction *tf = (TypeFunction *)fd->type;
+                    if (!tf->isref && e2)
+                        goto Leproplvalue;
+                }
+            }
+            if (fd)
+            {
+                Expression *e = new CallExp(loc, e1);
+                if (e2)
+                    e = new AssignExp(loc, e, e2);
+                return semantic(e, sc);
+            }
+        }
+        if (e2)
+            goto Leprop;
+    }
+    else if (e1->op == TOKdotti)
+    {
+        DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
+        if (!dti->findTempDecl(sc))
+            goto Leprop;
+        if (!dti->ti->semanticTiargs(sc))
+            goto Leprop;
+        tiargs = dti->ti->tiargs;
+        tthis  = dti->e1->type;
+        if ((os = dti->ti->tempdecl->isOverloadSet()) != NULL)
+            goto Los;
+        if ((s = dti->ti->tempdecl) != NULL)
+            goto Lfd;
+    }
+    else if (e1->op == TOKdottd)
+    {
+        DotTemplateExp *dte = (DotTemplateExp *)e1;
+        s      = dte->td;
+        tiargs = NULL;
+        tthis  = dte->e1->type;
+        goto Lfd;
+    }
+    else if (e1->op == TOKscope)
+    {
+        s = ((ScopeExp *)e1)->sds;
+        if (s->isTemplateDeclaration())
+        {
+            tiargs = NULL;
+            tthis  = NULL;
+            goto Lfd;
+        }
+        TemplateInstance *ti = s->isTemplateInstance();
+        if (ti && !ti->semanticRun && ti->tempdecl)
+        {
+            //assert(ti->needsTypeInference(sc));
+            if (!ti->semanticTiargs(sc))
+                goto Leprop;
+            tiargs = ti->tiargs;
+            tthis  = NULL;
+            if ((os = ti->tempdecl->isOverloadSet()) != NULL)
+                goto Los;
+            if ((s = ti->tempdecl) != NULL)
+                goto Lfd;
+        }
+    }
+    else if (e1->op == TOKtemplate)
+    {
+        s      = ((TemplateExp *)e1)->td;
+        tiargs = NULL;
+        tthis  = NULL;
+        goto Lfd;
+    }
+    else if (e1->op == TOKdotvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
+    {
+        DotVarExp *dve = (DotVarExp *)e1;
+        s      = dve->var->isFuncDeclaration();
+        tiargs = NULL;
+        tthis  = dve->e1->type;
+        goto Lfd;
+    }
+    else if (e1->op == TOKvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
+    {
+        s      = ((VarExp *)e1)->var->isFuncDeclaration();
+        tiargs = NULL;
+        tthis  = NULL;
+    Lfd:
+        assert(s);
+        if (e2)
+        {
+            e2 = semantic(e2, sc);
+            if (e2->op == TOKerror)
+                return new ErrorExp();
+            e2 = resolveProperties(sc, e2);
+
+            Expressions a;
+            a.push(e2);
+
+            FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, 1);
+            if (fd && fd->type)
+            {
+                if (fd->errors)
+                    return new ErrorExp();
+                assert(fd->type->ty == Tfunction);
+                TypeFunction *tf = (TypeFunction *)fd->type;
+                Expression *e = new CallExp(loc, e1, e2);
+                return semantic(e, sc);
+            }
+        }
+        {
+            FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, NULL, 1);
+            if (fd && fd->type)
+            {
+                if (fd->errors)
+                    return new ErrorExp();
+                assert(fd->type->ty == Tfunction);
+                TypeFunction *tf = (TypeFunction *)fd->type;
+                if (!e2 || tf->isref)
+                {
+                    Expression *e = new CallExp(loc, e1);
+                    if (e2)
+                        e = new AssignExp(loc, e, e2);
+                    return semantic(e, sc);
+                }
+            }
+        }
+        if (FuncDeclaration *fd = s->isFuncDeclaration())
+        {
+            // Keep better diagnostic message for invalid property usage of functions
+            assert(fd->type->ty == Tfunction);
+            TypeFunction *tf = (TypeFunction *)fd->type;
+            Expression *e = new CallExp(loc, e1, e2);
+            return semantic(e, sc);
+        }
+        if (e2)
+            goto Leprop;
+    }
+    if (e1->op == TOKvar)
+    {
+        VarExp *ve = (VarExp *)e1;
+        VarDeclaration *v = ve->var->isVarDeclaration();
+        if (v && ve->checkPurity(sc, v))
+            return new ErrorExp();
+    }
+    if (e2)
+        return NULL;
+
+    if (e1->type &&
+        e1->op != TOKtype)      // function type is not a property
+    {
+        /* Look for e1 being a lazy parameter; rewrite as delegate call
+         */
+        if (e1->op == TOKvar)
+        {
+            VarExp *ve = (VarExp *)e1;
+
+            if (ve->var->storage_class & STClazy)
+            {
+                Expression *e = new CallExp(loc, e1);
+                return semantic(e, sc);
+            }
+        }
+        else if (e1->op == TOKdotvar)
+        {
+            // Check for reading overlapped pointer field in @safe code.
+            if (checkUnsafeAccess(sc, e1, true, true))
+                return new ErrorExp();
+        }
+        else if (e1->op == TOKdot)
+        {
+            e1->error("expression has no value");
+            return new ErrorExp();
+        }
+        else if (e1->op == TOKcall)
+        {
+            CallExp *ce = (CallExp *)e1;
+            // Check for reading overlapped pointer field in @safe code.
+            if (checkUnsafeAccess(sc, ce->e1, true, true))
+                return new ErrorExp();
+        }
+    }
+
+    if (!e1->type)
+    {
+        error(loc, "cannot resolve type for %s", e1->toChars());
+        e1 = new ErrorExp();
+    }
+    return e1;
+
+Leprop:
+    error(loc, "not a property %s", e1->toChars());
+    return new ErrorExp();
+
+Leproplvalue:
+    error(loc, "%s is not an lvalue", e1->toChars());
+    return new ErrorExp();
+}
+
+Expression *resolveProperties(Scope *sc, Expression *e)
+{
+    //printf("resolveProperties(%s)\n", e->toChars());
+
+    e = resolvePropertiesX(sc, e);
+    if (e->checkRightThis(sc))
+        return new ErrorExp();
+    return e;
+}
+
+/******************************
+ * Check the tail CallExp is really property function call.
+ */
+bool checkPropertyCall(Expression *e, Expression *emsg)
+{
+    while (e->op == TOKcomma)
+        e = ((CommaExp *)e)->e2;
+
+    if (e->op == TOKcall)
+    {
+        CallExp *ce = (CallExp *)e;
+        TypeFunction *tf;
+        if (ce->f)
+        {
+            tf = (TypeFunction *)ce->f->type;
+            /* If a forward reference to ce->f, try to resolve it
+             */
+            if (!tf->deco && ce->f->_scope)
+            {
+                ce->f->semantic(ce->f->_scope);
+                tf = (TypeFunction *)ce->f->type;
+            }
+        }
+        else if (ce->e1->type->ty == Tfunction)
+            tf = (TypeFunction *)ce->e1->type;
+        else if (ce->e1->type->ty == Tdelegate)
+            tf = (TypeFunction *)ce->e1->type->nextOf();
+        else if (ce->e1->type->ty == Tpointer && ce->e1->type->nextOf()->ty == Tfunction)
+            tf = (TypeFunction *)ce->e1->type->nextOf();
+        else
+            assert(0);
+    }
+    return false;
+}
+
+/******************************
+ * If e1 is a property function (template), resolve it.
+ */
+
+Expression *resolvePropertiesOnly(Scope *sc, Expression *e1)
+{
+    //printf("e1 = %s %s\n", Token::toChars(e1->op), e1->toChars());
+    OverloadSet *os;
+    FuncDeclaration *fd;
+    TemplateDeclaration *td;
+
+    if (e1->op == TOKdot)
+    {
+        DotExp *de = (DotExp *)e1;
+        if (de->e2->op == TOKoverloadset)
+        {
+            os = ((OverExp *)de->e2)->vars;
+            goto Los;
+        }
+    }
+    else if (e1->op == TOKoverloadset)
+    {
+        os = ((OverExp *)e1)->vars;
+    Los:
+        assert(os);
+        for (size_t i = 0; i < os->a.dim; i++)
+        {
+            Dsymbol *s = os->a[i];
+            fd = s->isFuncDeclaration();
+            td = s->isTemplateDeclaration();
+            if (fd)
+            {
+                if (((TypeFunction *)fd->type)->isproperty)
+                    return resolveProperties(sc, e1);
+            }
+            else if (td && td->onemember &&
+                     (fd = td->onemember->isFuncDeclaration()) != NULL)
+            {
+                if (((TypeFunction *)fd->type)->isproperty ||
+                    (fd->storage_class2 & STCproperty) ||
+                    (td->_scope->stc & STCproperty))
+                {
+                    return resolveProperties(sc, e1);
+                }
+            }
+        }
+    }
+    else if (e1->op == TOKdotti)
+    {
+        DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
+        if (dti->ti->tempdecl && (td = dti->ti->tempdecl->isTemplateDeclaration()) != NULL)
+            goto Ltd;
+    }
+    else if (e1->op == TOKdottd)
+    {
+        td = ((DotTemplateExp *)e1)->td;
+        goto Ltd;
+    }
+    else if (e1->op == TOKscope)
+    {
+        Dsymbol *s = ((ScopeExp *)e1)->sds;
+        td = s->isTemplateDeclaration();
+        if (td)
+            goto Ltd;
+        TemplateInstance *ti = s->isTemplateInstance();
+        if (ti && !ti->semanticRun && ti->tempdecl)
+        {
+            if ((td = ti->tempdecl->isTemplateDeclaration()) != NULL)
+                goto Ltd;
+        }
+    }
+    else if (e1->op == TOKtemplate)
+    {
+        td = ((TemplateExp *)e1)->td;
+    Ltd:
+        assert(td);
+        if (td->onemember &&
+            (fd = td->onemember->isFuncDeclaration()) != NULL)
+        {
+            if (((TypeFunction *)fd->type)->isproperty ||
+                (fd->storage_class2 & STCproperty) ||
+                (td->_scope->stc & STCproperty))
+            {
+                return resolveProperties(sc, e1);
+            }
+        }
+    }
+    else if (e1->op == TOKdotvar && e1->type->ty == Tfunction)
+    {
+        DotVarExp *dve = (DotVarExp *)e1;
+        fd = dve->var->isFuncDeclaration();
+        goto Lfd;
+    }
+    else if (e1->op == TOKvar && e1->type->ty == Tfunction &&
+        (sc->intypeof || !((VarExp *)e1)->var->needThis()))
+    {
+        fd = ((VarExp *)e1)->var->isFuncDeclaration();
+    Lfd:
+        assert(fd);
+        if (((TypeFunction *)fd->type)->isproperty)
+            return resolveProperties(sc, e1);
+    }
+    return e1;
+}
+
+
+// TODO: merge with Scope::search::searchScopes()
+static Dsymbol *searchScopes(Scope *sc, Loc loc, Identifier *ident, int flags)
+{
+    Dsymbol *s = NULL;
+    for (Scope *scx = sc; scx; scx = scx->enclosing)
+    {
+        if (!scx->scopesym)
+            continue;
+        if (scx->scopesym->isModule())
+            flags |= SearchUnqualifiedModule;    // tell Module.search() that SearchLocalsOnly is to be obeyed
+        s = scx->scopesym->search(loc, ident, flags);
+        if (s)
+        {
+            // overload set contains only module scope symbols.
+            if (s->isOverloadSet())
+                break;
+            // selective/renamed imports also be picked up
+            if (AliasDeclaration *ad = s->isAliasDeclaration())
+            {
+                if (ad->_import)
+                    break;
+            }
+            // See only module scope symbols for UFCS target.
+            Dsymbol *p = s->toParent2();
+            if (p && p->isModule())
+                break;
+        }
+        s = NULL;
+
+        // Stop when we hit a module, but keep going if that is not just under the global scope
+        if (scx->scopesym->isModule() && !(scx->enclosing && !scx->enclosing->enclosing))
+            break;
+    }
+    return s;
+}
+
+/******************************
+ * Find symbol in accordance with the UFCS name look up rule
+ */
+
+Expression *searchUFCS(Scope *sc, UnaExp *ue, Identifier *ident)
+{
+    //printf("searchUFCS(ident = %s)\n", ident->toChars());
+    Loc loc = ue->loc;
+    int flags = 0;
+    Dsymbol *s = NULL;
+
+    if (sc->flags & SCOPEignoresymbolvisibility)
+        flags |= IgnoreSymbolVisibility;
+
+    Dsymbol *sold = NULL;
+    if (global.params.bug10378 || global.params.check10378)
+    {
+        sold = searchScopes(sc, loc, ident, flags | IgnoreSymbolVisibility);
+        if (!global.params.check10378)
+        {
+            s = sold;
+            goto Lsearchdone;
+        }
+    }
+
+    // First look in local scopes
+    s = searchScopes(sc, loc, ident, flags | SearchLocalsOnly);
+    if (!s)
+    {
+        // Second look in imported modules
+        s = searchScopes(sc, loc, ident, flags | SearchImportsOnly);
+
+        /** Still find private symbols, so that symbols that weren't access
+         * checked by the compiler remain usable.  Once the deprecation is over,
+         * this should be moved to search_correct instead.
+         */
+        if (!s && !(flags & IgnoreSymbolVisibility))
+        {
+            s = searchScopes(sc, loc, ident, flags | SearchLocalsOnly | IgnoreSymbolVisibility);
+            if (!s)
+                s = searchScopes(sc, loc, ident, flags | SearchImportsOnly | IgnoreSymbolVisibility);
+            if (s)
+                ::deprecation(loc, "%s is not visible from module %s", s->toPrettyChars(), sc->_module->toChars());
+        }
+    }
+    if (global.params.check10378)
+    {
+        Dsymbol *snew = s;
+        if (sold != snew)
+            Scope::deprecation10378(loc, sold, snew);
+        if (global.params.bug10378)
+            s = sold;
+    }
+Lsearchdone:
+
+    if (!s)
+        return ue->e1->type->Type::getProperty(loc, ident, 0);
+
+    FuncDeclaration *f = s->isFuncDeclaration();
+    if (f)
+    {
+        TemplateDeclaration *td = getFuncTemplateDecl(f);
+        if (td)
+        {
+            if (td->overroot)
+                td = td->overroot;
+            s = td;
+        }
+    }
+
+    if (ue->op == TOKdotti)
+    {
+        DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ue;
+        TemplateInstance *ti = new TemplateInstance(loc, s->ident);
+        ti->tiargs = dti->ti->tiargs;   // for better diagnostic message
+        if (!ti->updateTempDecl(sc, s))
+            return new ErrorExp();
+        return new ScopeExp(loc, ti);
+    }
+    else
+    {
+        //printf("-searchUFCS() %s\n", s->toChars());
+        return new DsymbolExp(loc, s);
+    }
+}
+
+/******************************
+ * check e is exp.opDispatch!(tiargs) or not
+ * It's used to switch to UFCS the semantic analysis path
+ */
+
+bool isDotOpDispatch(Expression *e)
+{
+    return e->op == TOKdotti &&
+           ((DotTemplateInstanceExp *)e)->ti->name == Id::opDispatch;
+}
+
+/******************************
+ * Pull out callable entity with UFCS.
+ */
+
+Expression *resolveUFCS(Scope *sc, CallExp *ce)
+{
+    Loc loc = ce->loc;
+    Expression *eleft;
+    Expression *e;
+
+    if (ce->e1->op == TOKdotid)
+    {
+        DotIdExp *die = (DotIdExp *)ce->e1;
+        Identifier *ident = die->ident;
+
+        Expression *ex = semanticX(die, sc);
+        if (ex != die)
+        {
+            ce->e1 = ex;
+            return NULL;
+        }
+        eleft = die->e1;
+
+        Type *t = eleft->type->toBasetype();
+        if (t->ty == Tarray || t->ty == Tsarray ||
+            t->ty == Tnull  || (t->isTypeBasic() && t->ty != Tvoid))
+        {
+            /* Built-in types and arrays have no callable properties, so do shortcut.
+             * It is necessary in: e.init()
+             */
+        }
+        else if (t->ty == Taarray)
+        {
+            if (ident == Id::remove)
+            {
+                /* Transform:
+                 *  aa.remove(arg) into delete aa[arg]
+                 */
+                if (!ce->arguments || ce->arguments->dim != 1)
+                {
+                    ce->error("expected key as argument to aa.remove()");
+                    return new ErrorExp();
+                }
+                if (!eleft->type->isMutable())
+                {
+                    ce->error("cannot remove key from %s associative array %s",
+                            MODtoChars(t->mod), eleft->toChars());
+                    return new ErrorExp();
+                }
+                Expression *key = (*ce->arguments)[0];
+                key = semantic(key, sc);
+                key = resolveProperties(sc, key);
+
+                TypeAArray *taa = (TypeAArray *)t;
+                key = key->implicitCastTo(sc, taa->index);
+
+                if (key->checkValue())
+                    return new ErrorExp();
+
+                semanticTypeInfo(sc, taa->index);
+
+                return new RemoveExp(loc, eleft, key);
+            }
+        }
+        else
+        {
+            if (Expression *ey = semanticY(die, sc, 1))
+            {
+                if (ey->op == TOKerror)
+                    return ey;
+                ce->e1 = ey;
+                if (isDotOpDispatch(ey))
+                {
+                    unsigned errors = global.startGagging();
+                    e = semantic(ce->syntaxCopy(), sc);
+                    if (!global.endGagging(errors))
+                        return e;
+                    /* fall down to UFCS */
+                }
+                else
+                    return NULL;
+            }
+        }
+        e = searchUFCS(sc, die, ident);
+    }
+    else if (ce->e1->op == TOKdotti)
+    {
+        DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ce->e1;
+        if (Expression *ey = semanticY(dti, sc, 1))
+        {
+            ce->e1 = ey;
+            return NULL;
+        }
+        eleft = dti->e1;
+        e = searchUFCS(sc, dti, dti->ti->name);
+    }
+    else
+        return NULL;
+
+    // Rewrite
+    ce->e1 = e;
+    if (!ce->arguments)
+        ce->arguments = new Expressions();
+    ce->arguments->shift(eleft);
+
+    return NULL;
+}
+
+/******************************
+ * Pull out property with UFCS.
+ */
+
+Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL)
+{
+    Loc loc = e1->loc;
+    Expression *eleft;
+    Expression *e;
+
+    if (e1->op == TOKdotid)
+    {
+        DotIdExp *die = (DotIdExp *)e1;
+        eleft = die->e1;
+        e = searchUFCS(sc, die, die->ident);
+    }
+    else if (e1->op == TOKdotti)
+    {
+        DotTemplateInstanceExp *dti;
+        dti = (DotTemplateInstanceExp *)e1;
+        eleft = dti->e1;
+        e = searchUFCS(sc, dti, dti->ti->name);
+    }
+    else
+        return NULL;
+
+    // Rewrite
+    if (e2)
+    {
+        // run semantic without gagging
+        e2 = semantic(e2, sc);
+
+        /* f(e1) = e2
+         */
+        Expression *ex = e->copy();
+        Expressions *a1 = new Expressions();
+        a1->setDim(1);
+        (*a1)[0] = eleft;
+        ex = new CallExp(loc, ex, a1);
+        ex = trySemantic(ex, sc);
+
+        /* f(e1, e2)
+         */
+        Expressions *a2 = new Expressions();
+        a2->setDim(2);
+        (*a2)[0] = eleft;
+        (*a2)[1] = e2;
+        e = new CallExp(loc, e, a2);
+        if (ex)
+        {   // if fallback setter exists, gag errors
+            e = trySemantic(e, sc);
+            if (!e)
+            {   checkPropertyCall(ex, e1);
+                ex = new AssignExp(loc, ex, e2);
+                return semantic(ex, sc);
+            }
+        }
+        else
+        {   // strict setter prints errors if fails
+            e = semantic(e, sc);
+        }
+        checkPropertyCall(e, e1);
+        return e;
+    }
+    else
+    {
+        /* f(e1)
+         */
+        Expressions *arguments = new Expressions();
+        arguments->setDim(1);
+        (*arguments)[0] = eleft;
+        e = new CallExp(loc, e, arguments);
+        e = semantic(e, sc);
+        checkPropertyCall(e, e1);
+        return semantic(e, sc);
+    }
+}
+
+/******************************
+ * Perform semantic() on an array of Expressions.
+ */
+
+bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors)
+{
+    bool err = false;
+    if (exps)
+    {
+        for (size_t i = 0; i < exps->dim; i++)
+        {
+            Expression *e = (*exps)[i];
+            if (e)
+            {
+                e = semantic(e, sc);
+                if (e->op == TOKerror)
+                    err = true;
+                if (preserveErrors || e->op != TOKerror)
+                    (*exps)[i] = e;
+            }
+        }
+    }
+    return err;
+}
+
+/****************************************
+ * Expand tuples.
+ * Input:
+ *      exps    aray of Expressions
+ * Output:
+ *      exps    rewritten in place
+ */
+
+void expandTuples(Expressions *exps)
+{
+    //printf("expandTuples()\n");
+    if (exps)
+    {
+        for (size_t i = 0; i < exps->dim; i++)
+        {
+            Expression *arg = (*exps)[i];
+            if (!arg)
+                continue;
+
+            // Look for tuple with 0 members
+            if (arg->op == TOKtype)
+            {
+                TypeExp *e = (TypeExp *)arg;
+                if (e->type->toBasetype()->ty == Ttuple)
+                {
+                    TypeTuple *tt = (TypeTuple *)e->type->toBasetype();
+
+                    if (!tt->arguments || tt->arguments->dim == 0)
+                    {
+                        exps->remove(i);
+                        if (i == exps->dim)
+                            return;
+                        i--;
+                        continue;
+                    }
+                }
+            }
+
+            // Inline expand all the tuples
+            while (arg->op == TOKtuple)
+            {
+                TupleExp *te = (TupleExp *)arg;
+                exps->remove(i);                // remove arg
+                exps->insert(i, te->exps);      // replace with tuple contents
+                if (i == exps->dim)
+                    return;             // empty tuple, no more arguments
+                (*exps)[i] = Expression::combine(te->e0, (*exps)[i]);
+                arg = (*exps)[i];
+            }
+        }
+    }
+}
+
+/****************************************
+ * Expand alias this tuples.
+ */
+
+TupleDeclaration *isAliasThisTuple(Expression *e)
+{
+    if (!e->type)
+        return NULL;
+
+    Type *t = e->type->toBasetype();
+Lagain:
+    if (Dsymbol *s = t->toDsymbol(NULL))
+    {
+        AggregateDeclaration *ad = s->isAggregateDeclaration();
+        if (ad)
+        {
+            s = ad->aliasthis;
+            if (s && s->isVarDeclaration())
+            {
+                TupleDeclaration *td = s->isVarDeclaration()->toAlias()->isTupleDeclaration();
+                if (td && td->isexp)
+                    return td;
+            }
+            if (Type *att = t->aliasthisOf())
+            {
+                t = att;
+                goto Lagain;
+            }
+        }
+    }
+    return NULL;
+}
+
+int expandAliasThisTuples(Expressions *exps, size_t starti)
+{
+    if (!exps || exps->dim == 0)
+        return -1;
+
+    for (size_t u = starti; u < exps->dim; u++)
+    {
+        Expression *exp = (*exps)[u];
+        TupleDeclaration *td = isAliasThisTuple(exp);
+        if (td)
+        {
+            exps->remove(u);
+            for (size_t i = 0; i<td->objects->dim; ++i)
+            {
+                Expression *e = isExpression((*td->objects)[i]);
+                assert(e);
+                assert(e->op == TOKdsymbol);
+                DsymbolExp *se = (DsymbolExp *)e;
+                Declaration *d = se->s->isDeclaration();
+                assert(d);
+                e = new DotVarExp(exp->loc, exp, d);
+                assert(d->type);
+                e->type = d->type;
+                exps->insert(u + i, e);
+            }
+    #if 0
+            printf("expansion ->\n");
+            for (size_t i = 0; i<exps->dim; ++i)
+            {
+                Expression *e = (*exps)[i];
+                printf("\texps[%d] e = %s %s\n", i, Token::tochars[e->op], e->toChars());
+            }
+    #endif
+            return (int)u;
+        }
+    }
+
+    return -1;
+}
+
+/****************************************
+ * The common type is determined by applying ?: to each pair.
+ * Output:
+ *      exps[]  properties resolved, implicitly cast to common type, rewritten in place
+ *      *pt     if pt is not NULL, set to the common type
+ * Returns:
+ *      true    a semantic error was detected
+ */
+
+bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt)
+{
+    /* Still have a problem with:
+     *  ubyte[][] = [ cast(ubyte[])"hello", [1]];
+     * which works if the array literal is initialized top down with the ubyte[][]
+     * type, but fails with this function doing bottom up typing.
+     */
+    //printf("arrayExpressionToCommonType()\n");
+    IntegerExp integerexp(0);
+    CondExp condexp(Loc(), &integerexp, NULL, NULL);
+
+    Type *t0 = NULL;
+    Expression *e0 = NULL;      // dead-store to prevent spurious warning
+    size_t j0 = ~0;             // dead-store to prevent spurious warning
+    for (size_t i = 0; i < exps->dim; i++)
+    {
+        Expression *e = (*exps)[i];
+        if (!e)
+            continue;
+
+        e = resolveProperties(sc, e);
+        if (!e->type)
+        {
+            e->error("%s has no value", e->toChars());
+            t0 = Type::terror;
+            continue;
+        }
+        if (e->op == TOKtype)
+        {
+            e->checkValue();    // report an error "type T has no value"
+            t0 = Type::terror;
+            continue;
+        }
+        if (e->type->ty == Tvoid)
+        {
+            // void expressions do not concur to the determination of the common
+            // type.
+            continue;
+        }
+        if (checkNonAssignmentArrayOp(e))
+        {
+            t0 = Type::terror;
+            continue;
+        }
+
+        e = doCopyOrMove(sc, e);
+
+        if (t0 && !t0->equals(e->type))
+        {
+            /* This applies ?: to merge the types. It's backwards;
+             * ?: should call this function to merge types.
+             */
+            condexp.type = NULL;
+            condexp.e1 = e0;
+            condexp.e2 = e;
+            condexp.loc = e->loc;
+            Expression *ex = semantic(&condexp, sc);
+            if (ex->op == TOKerror)
+                e = ex;
+            else
+            {
+                (*exps)[j0] = condexp.e1;
+                e = condexp.e2;
+            }
+        }
+        j0 = i;
+        e0 = e;
+        t0 = e->type;
+        if (e->op != TOKerror)
+            (*exps)[i] = e;
+    }
+
+    if (!t0)
+        t0 = Type::tvoid;               // [] is typed as void[]
+    else if (t0->ty != Terror)
+    {
+        for (size_t i = 0; i < exps->dim; i++)
+        {
+            Expression *e = (*exps)[i];
+            if (!e)
+                continue;
+
+            e = e->implicitCastTo(sc, t0);
+            //assert(e->op != TOKerror);
+            if (e->op == TOKerror)
+            {
+                /* Bugzilla 13024: a workaround for the bug in typeMerge -
+                 * it should paint e1 and e2 by deduced common type,
+                 * but doesn't in this particular case.
+                 */
+                t0 = Type::terror;
+                break;
+            }
+            (*exps)[i] = e;
+        }
+    }
+    if (pt)
+        *pt = t0;
+
+    return (t0 == Type::terror);
+}
+
+/****************************************
+ * Get TemplateDeclaration enclosing FuncDeclaration.
+ */
+
+TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s)
+{
+    FuncDeclaration *f = s->isFuncDeclaration();
+    if (f && f->parent)
+    {
+        TemplateInstance *ti = f->parent->isTemplateInstance();
+        if (ti && !ti->isTemplateMixin() &&
+            ti->tempdecl && ((TemplateDeclaration *)ti->tempdecl)->onemember &&
+            ti->tempdecl->ident == f->ident)
+        {
+            return (TemplateDeclaration *)ti->tempdecl;
+        }
+    }
+    return NULL;
+}
+
+/****************************************
+ * Preprocess arguments to function.
+ * Output:
+ *      exps[]  tuples expanded, properties resolved, rewritten in place
+ * Returns:
+ *      true    a semantic error occurred
+ */
+
+bool preFunctionParameters(Loc loc, Scope *sc, Expressions *exps)
+{
+    bool err = false;
+    if (exps)
+    {
+        expandTuples(exps);
+
+        for (size_t i = 0; i < exps->dim; i++)
+        {
+            Expression *arg = (*exps)[i];
+
+            arg = resolveProperties(sc, arg);
+            if (arg->op == TOKtype)
+            {
+                arg->error("cannot pass type %s as a function argument", arg->toChars());
+                arg = new ErrorExp();
+                err = true;
+            }
+            else if (checkNonAssignmentArrayOp(arg))
+            {
+                arg = new ErrorExp();
+                err = true;
+            }
+            (*exps)[i] = arg;
+        }
+    }
+    return err;
+}
+
+/************************************************
+ * If we want the value of this expression, but do not want to call
+ * the destructor on it.
+ */
+
+Expression *valueNoDtor(Expression *e)
+{
+    if (e->op == TOKcall)
+    {
+        /* The struct value returned from the function is transferred
+         * so do not call the destructor on it.
+         * Recognize:
+         *       ((S _ctmp = S.init), _ctmp).this(...)
+         * and make sure the destructor is not called on _ctmp
+         * BUG: if e is a CommaExp, we should go down the right side.
+         */
+        CallExp *ce = (CallExp *)e;
+        if (ce->e1->op == TOKdotvar)
+        {
+            DotVarExp *dve = (DotVarExp *)ce->e1;
+            if (dve->var->isCtorDeclaration())
+            {
+                // It's a constructor call
+                if (dve->e1->op == TOKcomma)
+                {
+                    CommaExp *comma = (CommaExp *)dve->e1;
+                    if (comma->e2->op == TOKvar)
+                    {
+                        VarExp *ve = (VarExp *)comma->e2;
+                        VarDeclaration *ctmp = ve->var->isVarDeclaration();
+                        if (ctmp)
+                        {
+                            ctmp->storage_class |= STCnodtor;
+                            assert(!ce->isLvalue());
+                        }
+                    }
+                }
+            }
+        }
+    }
+    else if (e->op == TOKvar)
+    {
+        VarDeclaration *vtmp = ((VarExp *)e)->var->isVarDeclaration();
+        if (vtmp && vtmp->storage_class & STCrvalue)
+        {
+            vtmp->storage_class |= STCnodtor;
+        }
+    }
+    return e;
+}
+
+/********************************************
+ * Issue an error if default construction is disabled for type t.
+ * Default construction is required for arrays and 'out' parameters.
+ * Returns:
+ *      true    an error was issued
+ */
+bool checkDefCtor(Loc loc, Type *t)
+{
+    t = t->baseElemOf();
+    if (t->ty == Tstruct)
+    {
+        StructDeclaration *sd = ((TypeStruct *)t)->sym;
+        if (sd->noDefaultCtor)
+        {
+            sd->error(loc, "default construction is disabled");
+            return true;
+        }
+    }
+    return false;
+}
+
+/*********************************************
+ * If e is an instance of a struct, and that struct has a copy constructor,
+ * rewrite e as:
+ *    (tmp = e),tmp
+ * Input:
+ *      sc      just used to specify the scope of created temporary variable
+ */
+Expression *callCpCtor(Scope *sc, Expression *e)
+{
+    Type *tv = e->type->baseElemOf();
+    if (tv->ty == Tstruct)
+    {
+        StructDeclaration *sd = ((TypeStruct *)tv)->sym;
+        if (sd->postblit)
+        {
+            /* Create a variable tmp, and replace the argument e with:
+             *      (tmp = e),tmp
+             * and let AssignExp() handle the construction.
+             * This is not the most efficent, ideally tmp would be constructed
+             * directly onto the stack.
+             */
+            VarDeclaration *tmp = copyToTemp(STCrvalue, "__copytmp", e);
+            tmp->storage_class |= STCnodtor;
+            tmp->semantic(sc);
+            Expression *de = new DeclarationExp(e->loc, tmp);
+            Expression *ve = new VarExp(e->loc, tmp);
+            de->type = Type::tvoid;
+            ve->type = e->type;
+            e = Expression::combine(de, ve);
+        }
+    }
+    return e;
+}
+
+/************************************************
+ * Handle the postblit call on lvalue, or the move of rvalue.
+ */
+Expression *doCopyOrMove(Scope *sc, Expression *e)
+{
+    if (e->op == TOKquestion)
+    {
+        CondExp *ce = (CondExp *)e;
+        ce->e1 = doCopyOrMove(sc, ce->e1);
+        ce->e2 = doCopyOrMove(sc, ce->e2);
+    }
+    else
+    {
+        e = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
+    }
+    return e;
+}
+
+/****************************************
+ * Now that we know the exact type of the function we're calling,
+ * the arguments[] need to be adjusted:
+ *      1. implicitly convert argument to the corresponding parameter type
+ *      2. add default arguments for any missing arguments
+ *      3. do default promotions on arguments corresponding to ...
+ *      4. add hidden _arguments[] argument
+ *      5. call copy constructor for struct value arguments
+ * Input:
+ *      tf      type of the function
+ *      fd      the function being called, NULL if called indirectly
+ * Output:
+ *      *prettype return type of function
+ *      *peprefix expression to execute before arguments[] are evaluated, NULL if none
+ * Returns:
+ *      true    errors happened
+ */
+
+bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
+        Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix)
+{
+    //printf("functionParameters()\n");
+    assert(arguments);
+    assert(fd || tf->next);
+    size_t nargs = arguments ? arguments->dim : 0;
+    size_t nparams = Parameter::dim(tf->parameters);
+    unsigned olderrors = global.errors;
+    bool err = false;
+    *prettype = Type::terror;
+    Expression *eprefix = NULL;
+    *peprefix = NULL;
+
+    if (nargs > nparams && tf->varargs == 0)
+    {
+        error(loc, "expected %llu arguments, not %llu for non-variadic function type %s", (ulonglong)nparams, (ulonglong)nargs, tf->toChars());
+        return true;
+    }
+
+    // If inferring return type, and semantic3() needs to be run if not already run
+    if (!tf->next && fd->inferRetType)
+    {
+        fd->functionSemantic();
+    }
+    else if (fd && fd->parent)
+    {
+        TemplateInstance *ti = fd->parent->isTemplateInstance();
+        if (ti && ti->tempdecl)
+        {
+            fd->functionSemantic3();
+        }
+    }
+    bool isCtorCall = fd && fd->needThis() && fd->isCtorDeclaration();
+
+    size_t n = (nargs > nparams) ? nargs : nparams;   // n = max(nargs, nparams)
+
+    /* If the function return type has wildcards in it, we'll need to figure out the actual type
+     * based on the actual argument types.
+     */
+    MOD wildmatch = 0;
+    if (tthis && tf->isWild() && !isCtorCall)
+    {
+        Type *t = tthis;
+        if (t->isImmutable())
+            wildmatch = MODimmutable;
+        else if (t->isWildConst())
+            wildmatch = MODwildconst;
+        else if (t->isWild())
+            wildmatch = MODwild;
+        else if (t->isConst())
+            wildmatch = MODconst;
+        else
+            wildmatch = MODmutable;
+    }
+
+    int done = 0;
+    for (size_t i = 0; i < n; i++)
+    {
+        Expression *arg;
+
+        if (i < nargs)
+            arg = (*arguments)[i];
+        else
+            arg = NULL;
+
+        if (i < nparams)
+        {
+            Parameter *p = Parameter::getNth(tf->parameters, i);
+
+            if (!arg)
+            {
+                if (!p->defaultArg)
+                {
+                    if (tf->varargs == 2 && i + 1 == nparams)
+                        goto L2;
+                    error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
+                    return true;
+                }
+                arg = p->defaultArg;
+                arg = inlineCopy(arg, sc);
+                // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
+                arg = arg->resolveLoc(loc, sc);
+                arguments->push(arg);
+                nargs++;
+            }
+
+            if (tf->varargs == 2 && i + 1 == nparams)
+            {
+                //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars());
+                {
+                    MATCH m;
+                    if ((m = arg->implicitConvTo(p->type)) > MATCHnomatch)
+                    {
+                        if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()) >= m)
+                            goto L2;
+                        else if (nargs != nparams)
+                        {   error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
+                            return true;
+                        }
+                        goto L1;
+                    }
+                }
+             L2:
+                Type *tb = p->type->toBasetype();
+                Type *tret = p->isLazyArray();
+                switch (tb->ty)
+                {
+                    case Tsarray:
+                    case Tarray:
+                    {
+                        /* Create a static array variable v of type arg->type:
+                         *  T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
+                         *
+                         * The array literal in the initializer of the hidden variable
+                         * is now optimized. See Bugzilla 2356.
+                         */
+                        Type *tbn = ((TypeArray *)tb)->next;
+                        Type *tsa = tbn->sarrayOf(nargs - i);
+
+                        Expressions *elements = new Expressions();
+                        elements->setDim(nargs - i);
+                        for (size_t u = 0; u < elements->dim; u++)
+                        {
+                            Expression *a = (*arguments)[i + u];
+                            if (tret && a->implicitConvTo(tret))
+                            {
+                                a = a->implicitCastTo(sc, tret);
+                                a = a->optimize(WANTvalue);
+                                a = toDelegate(a, a->type, sc);
+                            }
+                            else
+                                a = a->implicitCastTo(sc, tbn);
+                            (*elements)[u] = a;
+                        }
+                        // Bugzilla 14395: Convert to a static array literal, or its slice.
+                        arg = new ArrayLiteralExp(loc, elements);
+                        arg->type = tsa;
+                        if (tb->ty == Tarray)
+                        {
+                            arg = new SliceExp(loc, arg, NULL, NULL);
+                            arg->type = p->type;
+                        }
+                        break;
+                    }
+                    case Tclass:
+                    {
+                        /* Set arg to be:
+                         *      new Tclass(arg0, arg1, ..., argn)
+                         */
+                        Expressions *args = new Expressions();
+                        args->setDim(nargs - i);
+                        for (size_t u = i; u < nargs; u++)
+                            (*args)[u - i] = (*arguments)[u];
+                        arg = new NewExp(loc, NULL, NULL, p->type, args);
+                        break;
+                    }
+                    default:
+                        if (!arg)
+                        {
+                            error(loc, "not enough arguments");
+                            return true;
+                        }
+                        break;
+                }
+                arg = semantic(arg, sc);
+                //printf("\targ = '%s'\n", arg->toChars());
+                arguments->setDim(i + 1);
+                (*arguments)[i] =  arg;
+                nargs = i + 1;
+                done = 1;
+            }
+
+        L1:
+            if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
+            {
+                bool isRef = (p->storageClass & (STCref | STCout)) != 0;
+                if (unsigned char wm = arg->type->deduceWild(p->type, isRef))
+                {
+                    if (wildmatch)
+                        wildmatch = MODmerge(wildmatch, wm);
+                    else
+                        wildmatch = wm;
+                    //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p->type->toChars(), arg->type->toChars(), wm, wildmatch);
+                }
+            }
+        }
+        if (done)
+            break;
+    }
+    if ((wildmatch == MODmutable || wildmatch == MODimmutable) &&
+        tf->next->hasWild() &&
+        (tf->isref || !tf->next->implicitConvTo(tf->next->immutableOf())))
+    {
+        if (fd)
+        {
+            /* If the called function may return the reference to
+             * outer inout data, it should be rejected.
+             *
+             * void foo(ref inout(int) x) {
+             *   ref inout(int) bar(inout(int)) { return x; }
+             *   struct S { ref inout(int) bar() inout { return x; } }
+             *   bar(int.init) = 1;  // bad!
+             *   S().bar() = 1;      // bad!
+             * }
+             */
+            FuncDeclaration *f;
+            if (AggregateDeclaration *ad = fd->isThis())
+            {
+                f = ad->toParent2()->isFuncDeclaration();
+                goto Linoutnest;
+            }
+            else if (fd->isNested())
+            {
+                f = fd->toParent2()->isFuncDeclaration();
+            Linoutnest:
+                for (; f; f = f->toParent2()->isFuncDeclaration())
+                {
+                    if (((TypeFunction *)f->type)->iswild)
+                        goto Linouterr;
+                }
+            }
+        }
+        else if (tf->isWild())
+        {
+        Linouterr:
+            const char *s = wildmatch == MODmutable ? "mutable" : MODtoChars(wildmatch);
+            error(loc, "modify inout to %s is not allowed inside inout function", s);
+            return true;
+        }
+    }
+
+    assert(nargs >= nparams);
+    for (size_t i = 0; i < nargs; i++)
+    {
+        Expression *arg = (*arguments)[i];
+        assert(arg);
+        if (i < nparams)
+        {
+            Parameter *p = Parameter::getNth(tf->parameters, i);
+
+            if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
+            {
+                Type *tprm = p->type;
+                if (p->type->hasWild())
+                    tprm = p->type->substWildTo(wildmatch);
+                if (!tprm->equals(arg->type))
+                {
+                    //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars());
+                    arg = arg->implicitCastTo(sc, tprm);
+                    arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
+                }
+            }
+            if (p->storageClass & STCref)
+            {
+                arg = arg->toLvalue(sc, arg);
+
+                // Look for mutable misaligned pointer, etc., in @safe mode
+                err |= checkUnsafeAccess(sc, arg, false, true);
+            }
+            else if (p->storageClass & STCout)
+            {
+                Type *t = arg->type;
+                if (!t->isMutable() || !t->isAssignable())  // check blit assignable
+                {
+                    arg->error("cannot modify struct %s with immutable members", arg->toChars());
+                    err = true;
+                }
+                else
+                {
+                    // Look for misaligned pointer, etc., in @safe mode
+                    err |= checkUnsafeAccess(sc, arg, false, true);
+                    err |= checkDefCtor(arg->loc, t);   // t must be default constructible
+                }
+                arg = arg->toLvalue(sc, arg);
+            }
+            else if (p->storageClass & STClazy)
+            {
+                // Convert lazy argument to a delegate
+                if (p->type->ty == Tvoid)
+                    arg = toDelegate(arg, p->type, sc);
+                else
+                    arg = toDelegate(arg, arg->type, sc);
+            }
+
+            //printf("arg: %s\n", arg->toChars());
+            //printf("type: %s\n", arg->type->toChars());
+            if (tf->parameterEscapes(p))
+            {
+                /* Argument value can escape from the called function.
+                 * Check arg to see if it matters.
+                 */
+                if (global.params.vsafe)
+                    err |= checkParamArgumentEscape(sc, fd, p->ident, arg, false);
+            }
+            else
+            {
+                /* Argument value cannot escape from the called function.
+                 */
+                Expression *a = arg;
+                if (a->op == TOKcast)
+                    a = ((CastExp *)a)->e1;
+
+                if (a->op == TOKfunction)
+                {
+                    /* Function literals can only appear once, so if this
+                     * appearance was scoped, there cannot be any others.
+                     */
+                    FuncExp *fe = (FuncExp *)a;
+                    fe->fd->tookAddressOf = 0;
+                }
+                else if (a->op == TOKdelegate)
+                {
+                    /* For passing a delegate to a scoped parameter,
+                     * this doesn't count as taking the address of it.
+                     * We only worry about 'escaping' references to the function.
+                     */
+                    DelegateExp *de = (DelegateExp *)a;
+                    if (de->e1->op == TOKvar)
+                    {   VarExp *ve = (VarExp *)de->e1;
+                        FuncDeclaration *f = ve->var->isFuncDeclaration();
+                        if (f)
+                        {   f->tookAddressOf--;
+                            //printf("tookAddressOf = %d\n", f->tookAddressOf);
+                        }
+                    }
+                }
+            }
+            arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
+        }
+        else
+        {
+            // These will be the trailing ... arguments
+
+            // If not D linkage, do promotions
+            if (tf->linkage != LINKd)
+            {
+                // Promote bytes, words, etc., to ints
+                arg = integralPromotions(arg, sc);
+
+                // Promote floats to doubles
+                switch (arg->type->ty)
+                {
+                    case Tfloat32:
+                        arg = arg->castTo(sc, Type::tfloat64);
+                        break;
+
+                    case Timaginary32:
+                        arg = arg->castTo(sc, Type::timaginary64);
+                        break;
+                }
+
+                if (tf->varargs == 1)
+                {
+                    const char *p = tf->linkage == LINKc ? "extern(C)" : "extern(C++)";
+                    if (arg->type->ty == Tarray)
+                    {
+                        arg->error("cannot pass dynamic arrays to %s vararg functions", p);
+                        err = true;
+                    }
+                    if (arg->type->ty == Tsarray)
+                    {
+                        arg->error("cannot pass static arrays to %s vararg functions", p);
+                        err = true;
+                    }
+                }
+            }
+
+            // Do not allow types that need destructors
+            if (arg->type->needsDestruction())
+            {
+                arg->error("cannot pass types that need destruction as variadic arguments");
+                err = true;
+            }
+
+            // Convert static arrays to dynamic arrays
+            // BUG: I don't think this is right for D2
+            Type *tb = arg->type->toBasetype();
+            if (tb->ty == Tsarray)
+            {
+                TypeSArray *ts = (TypeSArray *)tb;
+                Type *ta = ts->next->arrayOf();
+                if (ts->size(arg->loc) == 0)
+                    arg = new NullExp(arg->loc, ta);
+                else
+                    arg = arg->castTo(sc, ta);
+            }
+            if (tb->ty == Tstruct)
+            {
+                //arg = callCpCtor(sc, arg);
+            }
+
+            // Give error for overloaded function addresses
+            if (arg->op == TOKsymoff)
+            {   SymOffExp *se = (SymOffExp *)arg;
+                if (se->hasOverloads &&
+                    !se->var->isFuncDeclaration()->isUnique())
+                {   arg->error("function %s is overloaded", arg->toChars());
+                    err = true;
+                }
+            }
+            if (arg->checkValue())
+                err = true;
+            arg = arg->optimize(WANTvalue);
+        }
+        (*arguments)[i] = arg;
+    }
+
+    /* Remaining problems:
+     * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
+     *    implemented by calling a function) we'll defer this for now.
+     * 2. value structs (or static arrays of them) that need to be copy constructed
+     * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
+     *    function gets called (functions normally destroy their parameters)
+     * 2 and 3 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
+     * up properly. Pushing arguments on the stack then cannot fail.
+     */
+    if (1)
+    {
+        /* TODO: tackle problem 1)
+         */
+        const bool leftToRight = true; // TODO: something like !fd.isArrayOp
+        if (!leftToRight)
+            assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
+
+        const ptrdiff_t start = (leftToRight ? 0 : (ptrdiff_t)nargs - 1);
+        const ptrdiff_t end = (leftToRight ? (ptrdiff_t)nargs : -1);
+        const ptrdiff_t step = (leftToRight ? 1 : -1);
+
+        /* Compute indices of last throwing argument and first arg needing destruction.
+         * Used to not set up destructors unless an arg needs destruction on a throw
+         * in a later argument.
+         */
+        ptrdiff_t lastthrow = -1;
+        ptrdiff_t firstdtor = -1;
+        for (ptrdiff_t i = start; i != end; i += step)
+        {
+            Expression *arg = (*arguments)[i];
+            if (canThrow(arg, sc->func, false))
+                lastthrow = i;
+            if (firstdtor == -1 && arg->type->needsDestruction())
+            {
+                Parameter *p = (i >= nparams ? NULL : Parameter::getNth(tf->parameters, i));
+                if (!(p && (p->storageClass & (STClazy | STCref | STCout))))
+                    firstdtor = i;
+            }
+        }
+
+        /* Does problem 3) apply to this call?
+         */
+        const bool needsPrefix = (firstdtor >= 0 && lastthrow >= 0
+            && (lastthrow - firstdtor) * step > 0);
+
+        /* If so, initialize 'eprefix' by declaring the gate
+         */
+        VarDeclaration *gate = NULL;
+        if (needsPrefix)
+        {
+            // eprefix => bool __gate [= false]
+            Identifier *idtmp = Identifier::generateId("__gate");
+            gate = new VarDeclaration(loc, Type::tbool, idtmp, NULL);
+            gate->storage_class |= STCtemp | STCctfe | STCvolatile;
+            gate->semantic(sc);
+
+            Expression *ae = new DeclarationExp(loc, gate);
+            eprefix = semantic(ae, sc);
+        }
+
+        for (ptrdiff_t i = start; i != end; i += step)
+        {
+            Expression *arg = (*arguments)[i];
+
+            Parameter *parameter = (i >= nparams ? NULL : Parameter::getNth(tf->parameters, i));
+            const bool isRef = (parameter && (parameter->storageClass & (STCref | STCout)));
+            const bool isLazy = (parameter && (parameter->storageClass & STClazy));
+
+            /* Skip lazy parameters
+             */
+            if (isLazy)
+                continue;
+
+            /* Do we have a gate? Then we have a prefix and we're not yet past the last throwing arg.
+             * Declare a temporary variable for this arg and append that declaration to 'eprefix',
+             * which will implicitly take care of potential problem 2) for this arg.
+             * 'eprefix' will therefore finally contain all args up to and including the last
+             * potentially throwing arg, excluding all lazy parameters.
+             */
+            if (gate)
+            {
+                const bool needsDtor = (!isRef && arg->type->needsDestruction() && i != lastthrow);
+
+                /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
+                 */
+                VarDeclaration *tmp = tmp = copyToTemp(0,
+                    needsDtor ? "__pfx" : "__pfy",
+                    !isRef ? arg : arg->addressOf());
+                tmp->semantic(sc);
+
+                /* Modify the destructor so it only runs if gate==false, i.e.,
+                 * only if there was a throw while constructing the args
+                 */
+                if (!needsDtor)
+                {
+                    if (tmp->edtor)
+                    {
+                        assert(i == lastthrow);
+                        tmp->edtor = NULL;
+                    }
+                }
+                else
+                {
+                    // edtor => (__gate || edtor)
+                    assert(tmp->edtor);
+                    Expression *e = tmp->edtor;
+                    e = new OrOrExp(e->loc, new VarExp(e->loc, gate), e);
+                    tmp->edtor = semantic(e, sc);
+                    //printf("edtor: %s\n", tmp->edtor->toChars());
+                }
+
+                // eprefix => (eprefix, auto __pfx/y = arg)
+                DeclarationExp *ae = new DeclarationExp(loc, tmp);
+                eprefix = Expression::combine(eprefix, semantic(ae, sc));
+
+                // arg => __pfx/y
+                arg = new VarExp(loc, tmp);
+                arg = semantic(arg, sc);
+                if (isRef)
+                {
+                    arg = new PtrExp(loc, arg);
+                    arg = semantic(arg, sc);
+                }
+
+                /* Last throwing arg? Then finalize eprefix => (eprefix, gate = true),
+                 * i.e., disable the dtors right after constructing the last throwing arg.
+                 * From now on, the callee will take care of destructing the args because
+                 * the args are implicitly moved into function parameters.
+                 *
+                 * Set gate to null to let the next iterations know they don't need to
+                 * append to eprefix anymore.
+                 */
+                if (i == lastthrow)
+                {
+                    Expression *e = new AssignExp(gate->loc, new VarExp(gate->loc, gate), new IntegerExp(gate->loc, 1, Type::tbool));
+                    eprefix = Expression::combine(eprefix, semantic(e, sc));
+                    gate = NULL;
+                }
+            }
+            else
+            {
+                /* No gate, no prefix to append to.
+                 * Handle problem 2) by calling the copy constructor for value structs
+                 * (or static arrays of them) if appropriate.
+                 */
+                Type *tv = arg->type->baseElemOf();
+                if (!isRef && tv->ty == Tstruct)
+                    arg = doCopyOrMove(sc, arg);
+            }
+
+            (*arguments)[i] = arg;
+        }
+    }
+    //if (eprefix) printf("eprefix: %s\n", eprefix->toChars());
+
+    // If D linkage and variadic, add _arguments[] as first argument
+    if (tf->linkage == LINKd && tf->varargs == 1)
+    {
+        assert(arguments->dim >= nparams);
+
+        Parameters *args = new Parameters;
+        args->setDim(arguments->dim - nparams);
+        for (size_t i = 0; i < arguments->dim - nparams; i++)
+        {
+            Parameter *arg = new Parameter(STCin, (*arguments)[nparams + i]->type, NULL, NULL);
+            (*args)[i] = arg;
+        }
+
+        TypeTuple *tup = new TypeTuple(args);
+        Expression *e = new TypeidExp(loc, tup);
+        e = semantic(e, sc);
+        arguments->insert(0, e);
+    }
+
+    Type *tret = tf->next;
+    if (isCtorCall)
+    {
+        //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd->toChars(), fd->type->toChars(),
+        //    wildmatch, tf->isWild(), fd->isolateReturn());
+        if (!tthis)
+        {
+            assert(sc->intypeof || global.errors);
+            tthis = fd->isThis()->type->addMod(fd->type->mod);
+        }
+        if (tf->isWild() && !fd->isolateReturn())
+        {
+            if (wildmatch)
+                tret = tret->substWildTo(wildmatch);
+            int offset;
+            if (!tret->implicitConvTo(tthis) &&
+                !(MODimplicitConv(tret->mod, tthis->mod) && tret->isBaseOf(tthis, &offset) && offset == 0))
+            {
+                const char* s1 = tret ->isNaked() ? " mutable" : tret ->modToChars();
+                const char* s2 = tthis->isNaked() ? " mutable" : tthis->modToChars();
+                ::error(loc, "inout constructor %s creates%s object, not%s",
+                        fd->toPrettyChars(), s1, s2);
+                err = true;
+            }
+        }
+        tret = tthis;
+    }
+    else if (wildmatch)
+    {
+        /* Adjust function return type based on wildmatch
+         */
+        //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret->toChars());
+        tret = tret->substWildTo(wildmatch);
+    }
+    *prettype = tret;
+    *peprefix = eprefix;
+    return (err || olderrors != global.errors);
+}
+
+/******************************** Expression **************************/
+
+Expression::Expression(Loc loc, TOK op, int size)
+{
+    //printf("Expression::Expression(op = %d) this = %p\n", op, this);
+    this->loc = loc;
+    this->op = op;
+    this->size = (unsigned char)size;
+    this->parens = 0;
+    type = NULL;
+}
+
+void Expression::_init()
+{
+    CTFEExp::cantexp = new CTFEExp(TOKcantexp);
+    CTFEExp::voidexp = new CTFEExp(TOKvoidexp);
+    CTFEExp::breakexp = new CTFEExp(TOKbreak);
+    CTFEExp::continueexp = new CTFEExp(TOKcontinue);
+    CTFEExp::gotoexp = new CTFEExp(TOKgoto);
+}
+
+Expression *Expression::syntaxCopy()
+{
+    //printf("Expression::syntaxCopy()\n");
+    //print();
+    return copy();
+}
+
+/*********************************
+ * Does *not* do a deep copy.
+ */
+
+Expression *Expression::copy()
+{
+    Expression *e;
+    if (!size)
+    {
+#ifdef DEBUG
+        fprintf(stderr, "No expression copy for: %s\n", toChars());
+        printf("op = %d\n", op);
+        print();
+#endif
+        assert(0);
+    }
+    e = (Expression *)mem.xmalloc(size);
+    //printf("Expression::copy(op = %d) e = %p\n", op, e);
+    return (Expression *)memcpy((void*)e, (void*)this, size);
+}
+
+void Expression::print()
+{
+    fprintf(stderr, "%s\n", toChars());
+    fflush(stderr);
+}
+
+const char *Expression::toChars()
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+    toCBuffer(this, &buf, &hgs);
+    return buf.extractString();
+}
+
+void Expression::error(const char *format, ...) const
+{
+    if (type != Type::terror)
+    {
+        va_list ap;
+        va_start(ap, format);
+        ::verror(loc, format, ap);
+        va_end( ap );
+    }
+}
+
+void Expression::warning(const char *format, ...) const
+{
+    if (type != Type::terror)
+    {
+        va_list ap;
+        va_start(ap, format);
+        ::vwarning(loc, format, ap);
+        va_end( ap );
+    }
+}
+
+void Expression::deprecation(const char *format, ...) const
+{
+    if (type != Type::terror)
+    {
+        va_list ap;
+        va_start(ap, format);
+        ::vdeprecation(loc, format, ap);
+        va_end( ap );
+    }
+}
+
+/**********************************
+ * Combine e1 and e2 by CommaExp if both are not NULL.
+ */
+Expression *Expression::combine(Expression *e1, Expression *e2)
+{
+    if (e1)
+    {
+        if (e2)
+        {
+            e1 = new CommaExp(e1->loc, e1, e2);
+            e1->type = e2->type;
+        }
+    }
+    else
+        e1 = e2;
+    return e1;
+}
+
+/**********************************
+ * If 'e' is a tree of commas, returns the leftmost expression
+ * by stripping off it from the tree. The remained part of the tree
+ * is returned via *pe0.
+ * Otherwise 'e' is directly returned and *pe0 is set to NULL.
+ */
+Expression *Expression::extractLast(Expression *e, Expression **pe0)
+{
+    if (e->op != TOKcomma)
+    {
+        *pe0 = NULL;
+        return e;
+    }
+
+    CommaExp *ce = (CommaExp *)e;
+    if (ce->e2->op != TOKcomma)
+    {
+        *pe0 = ce->e1;
+        return ce->e2;
+    }
+    else
+    {
+        *pe0 = e;
+
+        Expression **pce = &ce->e2;
+        while (((CommaExp *)(*pce))->e2->op == TOKcomma)
+        {
+            pce = &((CommaExp *)(*pce))->e2;
+        }
+        assert((*pce)->op == TOKcomma);
+        ce = (CommaExp *)(*pce);
+        *pce = ce->e1;
+
+        return ce->e2;
+    }
+}
+
+dinteger_t Expression::toInteger()
+{
+    //printf("Expression %s\n", Token::toChars(op));
+    error("integer constant expression expected instead of %s", toChars());
+    return 0;
+}
+
+uinteger_t Expression::toUInteger()
+{
+    //printf("Expression %s\n", Token::toChars(op));
+    return (uinteger_t)toInteger();
+}
+
+real_t Expression::toReal()
+{
+    error("floating point constant expression expected instead of %s", toChars());
+    return CTFloat::zero;
+}
+
+real_t Expression::toImaginary()
+{
+    error("floating point constant expression expected instead of %s", toChars());
+    return CTFloat::zero;
+}
+
+complex_t Expression::toComplex()
+{
+    error("floating point constant expression expected instead of %s", toChars());
+    return complex_t(CTFloat::zero);
+}
+
+StringExp *Expression::toStringExp()
+{
+    return NULL;
+}
+
+/***************************************
+ * Return !=0 if expression is an lvalue.
+ */
+
+bool Expression::isLvalue()
+{
+    return false;
+}
+
+/*******************************
+ * Give error if we're not an lvalue.
+ * If we can, convert expression to be an lvalue.
+ */
+
+Expression *Expression::toLvalue(Scope *sc, Expression *e)
+{
+    if (!e)
+        e = this;
+    else if (!loc.filename)
+        loc = e->loc;
+
+    if (e->op == TOKtype)
+        error("%s '%s' is a type, not an lvalue", e->type->kind(), e->type->toChars());
+    else
+        error("%s is not an lvalue", e->toChars());
+
+    return new ErrorExp();
+}
+
+/***************************************
+ * Parameters:
+ *      sc:     scope
+ *      flag:   1: do not issue error message for invalid modification
+ * Returns:
+ *      0:      is not modifiable
+ *      1:      is modifiable in default == being related to type->isMutable()
+ *      2:      is modifiable, because this is a part of initializing.
+ */
+
+int Expression::checkModifiable(Scope *sc, int flag)
+{
+    return type ? 1 : 0;    // default modifiable
+}
+
+Expression *Expression::modifiableLvalue(Scope *sc, Expression *e)
+{
+    //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars());
+
+    // See if this expression is a modifiable lvalue (i.e. not const)
+    if (checkModifiable(sc) == 1)
+    {
+        assert(type);
+        if (!type->isMutable())
+        {
+            error("cannot modify %s expression %s", MODtoChars(type->mod), toChars());
+            return new ErrorExp();
+        }
+        else if (!type->isAssignable())
+        {
+            error("cannot modify struct %s %s with immutable members", toChars(), type->toChars());
+            return new ErrorExp();
+        }
+    }
+    return toLvalue(sc, e);
+}
+
+/****************************************
+ * Check that the expression has a valid type.
+ * If not, generates an error "... has no type".
+ * Returns:
+ *      true if the expression is not valid.
+ * Note:
+ *      When this function returns true, `checkValue()` should also return true.
+ */
+bool Expression::checkType()
+{
+    return false;
+}
+
+/****************************************
+ * Check that the expression has a valid value.
+ * If not, generates an error "... has no value".
+ * Returns:
+ *      true if the expression is not valid or has void type.
+ */
+bool Expression::checkValue()
+{
+    if (type && type->toBasetype()->ty == Tvoid)
+    {
+        error("expression %s is void and has no value", toChars());
+        //print(); halt();
+        if (!global.gag)
+            type = Type::terror;
+        return true;
+    }
+    return false;
+}
+
+bool Expression::checkScalar()
+{
+    if (op == TOKerror)
+        return true;
+    if (type->toBasetype()->ty == Terror)
+        return true;
+    if (!type->isscalar())
+    {
+        error("'%s' is not a scalar, it is a %s", toChars(), type->toChars());
+        return true;
+    }
+    return checkValue();
+}
+
+bool Expression::checkNoBool()
+{
+    if (op == TOKerror)
+        return true;
+    if (type->toBasetype()->ty == Terror)
+        return true;
+    if (type->toBasetype()->ty == Tbool)
+    {
+        error("operation not allowed on bool '%s'", toChars());
+        return true;
+    }
+    return false;
+}
+
+bool Expression::checkIntegral()
+{
+    if (op == TOKerror)
+        return true;
+    if (type->toBasetype()->ty == Terror)
+        return true;
+    if (!type->isintegral())
+    {
+        error("'%s' is not of integral type, it is a %s", toChars(), type->toChars());
+        return true;
+    }
+    return checkValue();
+}
+
+bool Expression::checkArithmetic()
+{
+    if (op == TOKerror)
+        return true;
+    if (type->toBasetype()->ty == Terror)
+        return true;
+    if (!type->isintegral() && !type->isfloating())
+    {
+        error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars());
+        return true;
+    }
+    return checkValue();
+}
+
+void Expression::checkDeprecated(Scope *sc, Dsymbol *s)
+{
+    s->checkDeprecated(loc, sc);
+}
+
+/*********************************************
+ * Calling function f.
+ * Check the purity, i.e. if we're in a pure function
+ * we can only call other pure functions.
+ * Returns true if error occurs.
+ */
+bool Expression::checkPurity(Scope *sc, FuncDeclaration *f)
+{
+    if (!sc->func)
+        return false;
+    if (sc->func == f)
+        return false;
+    if (sc->intypeof == 1)
+        return false;
+    if (sc->flags & (SCOPEctfe | SCOPEdebug))
+        return false;
+
+    /* Given:
+     * void f() {
+     *   pure void g() {
+     *     /+pure+/ void h() {
+     *       /+pure+/ void i() { }
+     *     }
+     *   }
+     * }
+     * g() can call h() but not f()
+     * i() can call h() and g() but not f()
+     */
+
+    // Find the closest pure parent of the calling function
+    FuncDeclaration *outerfunc = sc->func;
+    FuncDeclaration *calledparent = f;
+
+    if (outerfunc->isInstantiated())
+    {
+        // The attributes of outerfunc should be inferred from the call of f.
+    }
+    else if (f->isInstantiated())
+    {
+        // The attributes of f are inferred from its body.
+    }
+    else if (f->isFuncLiteralDeclaration())
+    {
+        // The attributes of f are always inferred in its declared place.
+    }
+    else
+    {
+        /* Today, static local functions are impure by default, but they cannot
+         * violate purity of enclosing functions.
+         *
+         *  auto foo() pure {      // non instantiated funciton
+         *    static auto bar() {  // static, without pure attribute
+         *      impureFunc();      // impure call
+         *      // Although impureFunc is called inside bar, f(= impureFunc)
+         *      // is not callable inside pure outerfunc(= foo <- bar).
+         *    }
+         *
+         *    bar();
+         *    // Although bar is called inside foo, f(= bar) is callable
+         *    // bacause calledparent(= foo) is same with outerfunc(= foo).
+         *  }
+         */
+
+        while (outerfunc->toParent2() &&
+               outerfunc->isPureBypassingInference() == PUREimpure &&
+               outerfunc->toParent2()->isFuncDeclaration())
+        {
+            outerfunc = outerfunc->toParent2()->isFuncDeclaration();
+            if (outerfunc->type->ty == Terror)
+                return true;
+        }
+        while (calledparent->toParent2() &&
+               calledparent->isPureBypassingInference() == PUREimpure &&
+               calledparent->toParent2()->isFuncDeclaration())
+        {
+            calledparent = calledparent->toParent2()->isFuncDeclaration();
+            if (calledparent->type->ty == Terror)
+                return true;
+        }
+    }
+
+    // If the caller has a pure parent, then either the called func must be pure,
+    // OR, they must have the same pure parent.
+    if (!f->isPure() && calledparent != outerfunc)
+    {
+        FuncDeclaration *ff = outerfunc;
+        if (sc->flags & SCOPEcompile ? ff->isPureBypassingInference() >= PUREweak : ff->setImpure())
+        {
+            error("pure %s '%s' cannot call impure %s '%s'",
+                ff->kind(), ff->toPrettyChars(), f->kind(), f->toPrettyChars());
+            return true;
+        }
+    }
+    return false;
+}
+
+/*******************************************
+ * Accessing variable v.
+ * Check for purity and safety violations.
+ * Returns true if error occurs.
+ */
+bool Expression::checkPurity(Scope *sc, VarDeclaration *v)
+{
+    //printf("v = %s %s\n", v->type->toChars(), v->toChars());
+
+    /* Look for purity and safety violations when accessing variable v
+     * from current function.
+     */
+    if (!sc->func)
+        return false;
+    if (sc->intypeof == 1)
+        return false;   // allow violations inside typeof(expression)
+    if (sc->flags & (SCOPEctfe | SCOPEdebug))
+        return false;   // allow violations inside compile-time evaluated expressions and debug conditionals
+    if (v->ident == Id::ctfe)
+        return false;   // magic variable never violates pure and safe
+    if (v->isImmutable())
+        return false;   // always safe and pure to access immutables...
+    if (v->isConst() && !v->isRef() && (v->isDataseg() || v->isParameter()) &&
+        v->type->implicitConvTo(v->type->immutableOf()))
+        return false;   // or const global/parameter values which have no mutable indirections
+    if (v->storage_class & STCmanifest)
+        return false;   // ...or manifest constants
+
+    bool err = false;
+    if (v->isDataseg())
+    {
+        // Bugzilla 7533: Accessing implicit generated __gate is pure.
+        if (v->ident == Id::gate)
+            return false;
+
+        /* Accessing global mutable state.
+         * Therefore, this function and all its immediately enclosing
+         * functions must be pure.
+         */
+        /* Today, static local functions are impure by default, but they cannot
+         * violate purity of enclosing functions.
+         *
+         *  auto foo() pure {      // non instantiated funciton
+         *    static auto bar() {  // static, without pure attribute
+         *      globalData++;      // impure access
+         *      // Although globalData is accessed inside bar,
+         *      // it is not accessible inside pure foo.
+         *    }
+         *  }
+         */
+        for (Dsymbol *s = sc->func; s; s = s->toParent2())
+        {
+            FuncDeclaration *ff = s->isFuncDeclaration();
+            if (!ff)
+                break;
+            if (sc->flags & SCOPEcompile ? ff->isPureBypassingInference() >= PUREweak : ff->setImpure())
+            {
+                error("pure %s '%s' cannot access mutable static data '%s'",
+                    ff->kind(), ff->toPrettyChars(), v->toChars());
+                err = true;
+                break;
+            }
+            /* If the enclosing is an instantiated function or a lambda, its
+             * attribute inference result is preferred.
+             */
+            if (ff->isInstantiated())
+                break;
+            if (ff->isFuncLiteralDeclaration())
+                break;
+        }
+    }
+    else
+    {
+        /* Given:
+         * void f() {
+         *   int fx;
+         *   pure void g() {
+         *     int gx;
+         *     /+pure+/ void h() {
+         *       int hx;
+         *       /+pure+/ void i() { }
+         *     }
+         *   }
+         * }
+         * i() can modify hx and gx but not fx
+         */
+
+        Dsymbol *vparent = v->toParent2();
+        for (Dsymbol *s = sc->func; !err && s; s = s->toParent2())
+        {
+            if (s == vparent)
+                break;
+
+            if (AggregateDeclaration *ad = s->isAggregateDeclaration())
+            {
+                if (ad->isNested())
+                    continue;
+                break;
+            }
+            FuncDeclaration *ff = s->isFuncDeclaration();
+            if (!ff)
+                break;
+            if (ff->isNested())
+            {
+                if (ff->type->isImmutable())
+                {
+                    error("pure immutable %s '%s' cannot access mutable data '%s'",
+                        ff->kind(), ff->toPrettyChars(), v->toChars());
+                    err = true;
+                    break;
+                }
+                continue;
+            }
+            if (ff->isThis())
+            {
+                if (ff->type->isImmutable())
+                {
+                    error("pure immutable %s '%s' cannot access mutable data '%s'",
+                        ff->kind(), ff->toPrettyChars(), v->toChars());
+                    err = true;
+                    break;
+                }
+                continue;
+            }
+            break;
+        }
+    }
+
+    /* Do not allow safe functions to access __gshared data
+     */
+    if (v->storage_class & STCgshared)
+    {
+        if (sc->func->setUnsafe())
+        {
+            error("safe %s '%s' cannot access __gshared data '%s'",
+                sc->func->kind(), sc->func->toChars(), v->toChars());
+            err = true;
+        }
+    }
+
+    return err;
+}
+
+/*********************************************
+ * Calling function f.
+ * Check the safety, i.e. if we're in a @safe function
+ * we can only call @safe or @trusted functions.
+ * Returns true if error occurs.
+ */
+bool Expression::checkSafety(Scope *sc, FuncDeclaration *f)
+{
+    if (!sc->func)
+        return false;
+    if (sc->func == f)
+        return false;
+    if (sc->intypeof == 1)
+        return false;
+    if (sc->flags & SCOPEctfe)
+        return false;
+
+    if (!f->isSafe() && !f->isTrusted())
+    {
+        if (sc->flags & SCOPEcompile ? sc->func->isSafeBypassingInference() : sc->func->setUnsafe())
+        {
+            if (loc.linnum == 0)  // e.g. implicitly generated dtor
+                loc = sc->func->loc;
+
+            error("@safe %s '%s' cannot call @system %s '%s'",
+                sc->func->kind(), sc->func->toPrettyChars(), f->kind(), f->toPrettyChars());
+            return true;
+        }
+    }
+    return false;
+}
+
+/*********************************************
+ * Calling function f.
+ * Check the @nogc-ness, i.e. if we're in a @nogc function
+ * we can only call other @nogc functions.
+ * Returns true if error occurs.
+ */
+bool Expression::checkNogc(Scope *sc, FuncDeclaration *f)
+{
+    if (!sc->func)
+        return false;
+    if (sc->func == f)
+        return false;
+    if (sc->intypeof == 1)
+        return false;
+    if (sc->flags & SCOPEctfe)
+        return false;
+
+    if (!f->isNogc())
+    {
+        if (sc->flags & SCOPEcompile ? sc->func->isNogcBypassingInference() : sc->func->setGC())
+        {
+            if (loc.linnum == 0)  // e.g. implicitly generated dtor
+                loc = sc->func->loc;
+
+            error("@nogc %s '%s' cannot call non-@nogc %s '%s'",
+                sc->func->kind(), sc->func->toPrettyChars(), f->kind(), f->toPrettyChars());
+            return true;
+        }
+    }
+    return false;
+}
+
+/********************************************
+ * Check that the postblit is callable if t is an array of structs.
+ * Returns true if error happens.
+ */
+bool Expression::checkPostblit(Scope *sc, Type *t)
+{
+    t = t->baseElemOf();
+    if (t->ty == Tstruct)
+    {
+        // Bugzilla 11395: Require TypeInfo generation for array concatenation
+        semanticTypeInfo(sc, t);
+
+        StructDeclaration *sd = ((TypeStruct *)t)->sym;
+        if (sd->postblit)
+        {
+            if (sd->postblit->storage_class & STCdisable)
+            {
+                sd->error(loc, "is not copyable because it is annotated with @disable");
+                return true;
+            }
+            //checkDeprecated(sc, sd->postblit);        // necessary?
+            checkPurity(sc, sd->postblit);
+            checkSafety(sc, sd->postblit);
+            checkNogc(sc, sd->postblit);
+            //checkAccess(sd, loc, sc, sd->postblit);   // necessary?
+            return false;
+        }
+    }
+    return false;
+}
+
+bool Expression::checkRightThis(Scope *sc)
+{
+    if (op == TOKerror)
+        return true;
+    if (op == TOKvar && type->ty != Terror)
+    {
+        VarExp *ve = (VarExp *)this;
+        if (isNeedThisScope(sc, ve->var))
+        {
+            //printf("checkRightThis sc->intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
+            //        sc->intypeof, sc->getStructClassScope(), func, fdthis);
+            error("need 'this' for '%s' of type '%s'", ve->var->toChars(), ve->var->type->toChars());
+            return true;
+        }
+    }
+    return false;
+}
+
+/*******************************
+ * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
+ * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
+ * Returns true if error occurs.
+ */
+bool Expression::checkReadModifyWrite(TOK rmwOp, Expression *ex)
+{
+    //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex->toChars() : "");
+    if (!type || !type->isShared())
+        return false;
+
+    // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
+    switch (rmwOp)
+    {
+        case TOKplusplus:
+        case TOKpreplusplus:
+            rmwOp = TOKaddass;
+            break;
+
+        case TOKminusminus:
+        case TOKpreminusminus:
+            rmwOp = TOKminass;
+            break;
+
+        default:
+            break;
+    }
+
+    deprecation("read-modify-write operations are not allowed for shared variables. "
+                "Use core.atomic.atomicOp!\"%s\"(%s, %s) instead.",
+                Token::tochars[rmwOp], toChars(), ex ? ex->toChars() : "1");
+    return false;
+
+    // note: enable when deprecation becomes an error.
+    // return true;
+}
+
+/*****************************
+ * If expression can be tested for true or false,
+ * returns the modified expression.
+ * Otherwise returns ErrorExp.
+ */
+Expression *Expression::toBoolean(Scope *sc)
+{
+    // Default is 'yes' - do nothing
+
+#ifdef DEBUG
+    if (!type)
+        print();
+    assert(type);
+#endif
+
+    Expression *e = this;
+    Type *t = type;
+    Type *tb = type->toBasetype();
+    Type *att = NULL;
+Lagain:
+    // Structs can be converted to bool using opCast(bool)()
+    if (tb->ty == Tstruct)
+    {
+        AggregateDeclaration *ad = ((TypeStruct *)tb)->sym;
+        /* Don't really need to check for opCast first, but by doing so we
+         * get better error messages if it isn't there.
+         */
+        Dsymbol *fd = search_function(ad, Id::_cast);
+        if (fd)
+        {
+            e = new CastExp(loc, e, Type::tbool);
+            e = semantic(e, sc);
+            return e;
+        }
+
+        // Forward to aliasthis.
+        if (ad->aliasthis && tb != att)
+        {
+            if (!att && tb->checkAliasThisRec())
+                att = tb;
+            e = resolveAliasThis(sc, e);
+            t = e->type;
+            tb = e->type->toBasetype();
+            goto Lagain;
+        }
+    }
+
+    if (!t->isBoolean())
+    {
+        if (tb != Type::terror)
+            error("expression %s of type %s does not have a boolean value", toChars(), t->toChars());
+        return new ErrorExp();
+    }
+    return e;
+}
+
+/******************************
+ * Take address of expression.
+ */
+
+Expression *Expression::addressOf()
+{
+    //printf("Expression::addressOf()\n");
+#ifdef DEBUG
+    assert(op == TOKerror || isLvalue());
+#endif
+    Expression *e = new AddrExp(loc, this);
+    e->type = type->pointerTo();
+    return e;
+}
+
+/******************************
+ * If this is a reference, dereference it.
+ */
+
+Expression *Expression::deref()
+{
+    //printf("Expression::deref()\n");
+    // type could be null if forward referencing an 'auto' variable
+    if (type && type->ty == Treference)
+    {
+        Expression *e = new PtrExp(loc, this);
+        e->type = ((TypeReference *)type)->next;
+        return e;
+    }
+    return this;
+}
+
+/********************************
+ * Does this expression statically evaluate to a boolean 'result' (true or false)?
+ */
+bool Expression::isBool(bool result)
+{
+    return false;
+}
+
+/****************************************
+ * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__ to loc.
+ */
+
+Expression *Expression::resolveLoc(Loc loc, Scope *sc)
+{
+    return this;
+}
+
+Expressions *Expression::arraySyntaxCopy(Expressions *exps)
+{
+    Expressions *a = NULL;
+    if (exps)
+    {
+        a = new Expressions();
+        a->setDim(exps->dim);
+        for (size_t i = 0; i < a->dim; i++)
+        {
+            Expression *e = (*exps)[i];
+            (*a)[i] = e ? e->syntaxCopy() : NULL;
+        }
+    }
+    return a;
+}
+
+/************************************************
+ * Destructors are attached to VarDeclarations.
+ * Hence, if expression returns a temp that needs a destructor,
+ * make sure and create a VarDeclaration for that temp.
+ */
+
+Expression *Expression::addDtorHook(Scope *sc)
+{
+    return this;
+}
+
+/******************************** IntegerExp **************************/
+
+IntegerExp::IntegerExp(Loc loc, dinteger_t value, Type *type)
+        : Expression(loc, TOKint64, sizeof(IntegerExp))
+{
+    //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : "");
+    assert(type);
+    if (!type->isscalar())
+    {
+        //printf("%s, loc = %d\n", toChars(), loc.linnum);
+        if (type->ty != Terror)
+            error("integral constant must be scalar type, not %s", type->toChars());
+        type = Type::terror;
+    }
+    this->type = type;
+    setInteger(value);
+}
+
+IntegerExp::IntegerExp(dinteger_t value)
+        : Expression(Loc(), TOKint64, sizeof(IntegerExp))
+{
+    this->type = Type::tint32;
+    this->value = (d_int32) value;
+}
+
+IntegerExp *IntegerExp::create(Loc loc, dinteger_t value, Type *type)
+{
+    return new IntegerExp(loc, value, type);
+}
+
+bool IntegerExp::equals(RootObject *o)
+{
+    if (this == o)
+        return true;
+    if (((Expression *)o)->op == TOKint64)
+    {
+        IntegerExp *ne = (IntegerExp *)o;
+        if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
+            value == ne->value)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+void IntegerExp::setInteger(dinteger_t value)
+{
+    this->value = value;
+    normalize();
+}
+
+void IntegerExp::normalize()
+{
+    /* 'Normalize' the value of the integer to be in range of the type
+     */
+    switch (type->toBasetype()->ty)
+    {
+        case Tbool:         value = (value != 0);           break;
+        case Tint8:         value = (d_int8)  value;        break;
+        case Tchar:
+        case Tuns8:         value = (d_uns8)  value;        break;
+        case Tint16:        value = (d_int16) value;        break;
+        case Twchar:
+        case Tuns16:        value = (d_uns16) value;        break;
+        case Tint32:        value = (d_int32) value;        break;
+        case Tdchar:
+        case Tuns32:        value = (d_uns32) value;        break;
+        case Tint64:        value = (d_int64) value;        break;
+        case Tuns64:        value = (d_uns64) value;        break;
+        case Tpointer:
+            if (Target::ptrsize == 4)
+                value = (d_uns32) value;
+            else if (Target::ptrsize == 8)
+                value = (d_uns64) value;
+            else
+                assert(0);
+            break;
+        default:
+            break;
+    }
+}
+
+dinteger_t IntegerExp::toInteger()
+{
+    normalize();   // necessary until we fix all the paints of 'type'
+    return value;
+}
+
+real_t IntegerExp::toReal()
+{
+    normalize();   // necessary until we fix all the paints of 'type'
+    Type *t = type->toBasetype();
+    if (t->ty == Tuns64)
+        return ldouble((d_uns64)value);
+    else
+        return ldouble((d_int64)value);
+}
+
+real_t IntegerExp::toImaginary()
+{
+    return CTFloat::zero;
+}
+
+complex_t IntegerExp::toComplex()
+{
+    return (complex_t)toReal();
+}
+
+bool IntegerExp::isBool(bool result)
+{
+    bool r = toInteger() != 0;
+    return result ? r : !r;
+}
+
+Expression *IntegerExp::toLvalue(Scope *sc, Expression *e)
+{
+    if (!e)
+        e = this;
+    else if (!loc.filename)
+        loc = e->loc;
+    e->error("constant %s is not an lvalue", e->toChars());
+    return new ErrorExp();
+}
+
+/******************************** ErrorExp **************************/
+
+/* Use this expression for error recovery.
+ * It should behave as a 'sink' to prevent further cascaded error messages.
+ */
+
+ErrorExp::ErrorExp()
+    : Expression(Loc(), TOKerror, sizeof(ErrorExp))
+{
+    type = Type::terror;
+}
+
+Expression *ErrorExp::toLvalue(Scope *sc, Expression *e)
+{
+    return this;
+}
+
+/******************************** RealExp **************************/
+
+RealExp::RealExp(Loc loc, real_t value, Type *type)
+        : Expression(loc, TOKfloat64, sizeof(RealExp))
+{
+    //printf("RealExp::RealExp(%Lg)\n", value);
+    this->value = value;
+    this->type = type;
+}
+
+RealExp *RealExp::create(Loc loc, real_t value, Type *type)
+{
+    return new RealExp(loc, value,type);
+}
+
+dinteger_t RealExp::toInteger()
+{
+    return (sinteger_t) toReal();
+}
+
+uinteger_t RealExp::toUInteger()
+{
+    return (uinteger_t) toReal();
+}
+
+real_t RealExp::toReal()
+{
+    return type->isreal() ? value : CTFloat::zero;
+}
+
+real_t RealExp::toImaginary()
+{
+    return type->isreal() ? CTFloat::zero : value;
+}
+
+complex_t RealExp::toComplex()
+{
+    return complex_t(toReal(), toImaginary());
+}
+
+/********************************
+ * Test to see if two reals are the same.
+ * Regard NaN's as equivalent.
+ * Regard +0 and -0 as different.
+ */
+
+int RealEquals(real_t x1, real_t x2)
+{
+    return (CTFloat::isNaN(x1) && CTFloat::isNaN(x2)) ||
+        CTFloat::isIdentical(x1, x2);
+}
+
+bool RealExp::equals(RootObject *o)
+{
+    if (this == o)
+        return true;
+    if (((Expression *)o)->op == TOKfloat64)
+    {
+        RealExp *ne = (RealExp *)o;
+        if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
+            RealEquals(value, ne->value))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool RealExp::isBool(bool result)
+{
+    return result ? (bool)value : !(bool)value;
+}
+
+/******************************** ComplexExp **************************/
+
+ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type)
+        : value(value), Expression(loc, TOKcomplex80, sizeof(ComplexExp))
+{
+    this->type = type;
+    //printf("ComplexExp::ComplexExp(%s)\n", toChars());
+}
+
+ComplexExp *ComplexExp::create(Loc loc, complex_t value, Type *type)
+{
+    return new ComplexExp(loc, value, type);
+}
+
+dinteger_t ComplexExp::toInteger()
+{
+    return (sinteger_t) toReal();
+}
+
+uinteger_t ComplexExp::toUInteger()
+{
+    return (uinteger_t) toReal();
+}
+
+real_t ComplexExp::toReal()
+{
+    return creall(value);
+}
+
+real_t ComplexExp::toImaginary()
+{
+    return cimagl(value);
+}
+
+complex_t ComplexExp::toComplex()
+{
+    return value;
+}
+
+bool ComplexExp::equals(RootObject *o)
+{
+    if (this == o)
+        return true;
+    if (((Expression *)o)->op == TOKcomplex80)
+    {
+        ComplexExp *ne = (ComplexExp *)o;
+        if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
+            RealEquals(creall(value), creall(ne->value)) &&
+            RealEquals(cimagl(value), cimagl(ne->value)))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool ComplexExp::isBool(bool result)
+{
+    if (result)
+        return (bool)(value);
+    else
+        return !value;
+}
+
+/******************************** IdentifierExp **************************/
+
+IdentifierExp::IdentifierExp(Loc loc, Identifier *ident)
+        : Expression(loc, TOKidentifier, sizeof(IdentifierExp))
+{
+    this->ident = ident;
+}
+
+IdentifierExp *IdentifierExp::create(Loc loc, Identifier *ident)
+{
+    return new IdentifierExp(loc, ident);
+}
+
+bool IdentifierExp::isLvalue()
+{
+    return true;
+}
+
+Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e)
+{
+    return this;
+}
+
+/******************************** DollarExp **************************/
+
+DollarExp::DollarExp(Loc loc)
+        : IdentifierExp(loc, Id::dollar)
+{
+}
+
+/******************************** DsymbolExp **************************/
+
+DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s, bool hasOverloads)
+        : Expression(loc, TOKdsymbol, sizeof(DsymbolExp))
+{
+    this->s = s;
+    this->hasOverloads = hasOverloads;
+}
+
+/****************************************
+ * Resolve a symbol `s` and wraps it in an expression object.
+ * Params:
+ *      hasOverloads = works if the aliased symbol is a function.
+ *          true:  it's overloaded and will be resolved later.
+ *          false: it's exact function symbol.
+ */
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads)
+{
+#if LOGSEMANTIC
+    printf("DsymbolExp::resolve(%s %s)\n", s->kind(), s->toChars());
+#endif
+
+Lagain:
+    Expression *e;
+
+    //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
+    //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind());
+    Dsymbol *olds = s;
+    Declaration *d = s->isDeclaration();
+    if (d && (d->storage_class & STCtemplateparameter))
+    {
+        s = s->toAlias();
+    }
+    else
+    {
+        if (!s->isFuncDeclaration())        // functions are checked after overloading
+            s->checkDeprecated(loc, sc);
+
+        // Bugzilla 12023: if 's' is a tuple variable, the tuple is returned.
+        s = s->toAlias();
+
+        //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis());
+        if (s != olds && !s->isFuncDeclaration())
+            s->checkDeprecated(loc, sc);
+    }
+
+    if (EnumMember *em = s->isEnumMember())
+    {
+        return em->getVarExp(loc, sc);
+    }
+    if (VarDeclaration *v = s->isVarDeclaration())
+    {
+        //printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars());
+        if (!v->type ||                  // during variable type inference
+            !v->type->deco && v->inuse)  // during variable type semantic
+        {
+            if (v->inuse)    // variable type depends on the variable itself
+                ::error(loc, "circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+            else             // variable type cannot be determined
+                ::error(loc, "forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+            return new ErrorExp();
+        }
+        if (v->type->ty == Terror)
+            return new ErrorExp();
+
+        if ((v->storage_class & STCmanifest) && v->_init)
+        {
+            if (v->inuse)
+            {
+                ::error(loc, "circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+                return new ErrorExp();
+            }
+
+            e = v->expandInitializer(loc);
+            v->inuse++;
+            e = semantic(e, sc);
+            v->inuse--;
+            return e;
+        }
+
+        // Change the ancestor lambdas to delegate before hasThis(sc) call.
+        if (v->checkNestedReference(sc, loc))
+            return new ErrorExp();
+
+        if (v->needThis() && hasThis(sc))
+            e = new DotVarExp(loc, new ThisExp(loc), v);
+        else
+            e = new VarExp(loc, v);
+        e = semantic(e, sc);
+        return e;
+    }
+    if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
+    {
+        //printf("'%s' is a function literal\n", fld->toChars());
+        e = new FuncExp(loc, fld);
+        return semantic(e, sc);
+    }
+    if (FuncDeclaration *f = s->isFuncDeclaration())
+    {
+        f = f->toAliasFunc();
+        if (!f->functionSemantic())
+            return new ErrorExp();
+
+        if (!hasOverloads && f->checkForwardRef(loc))
+            return new ErrorExp();
+
+        FuncDeclaration *fd = s->isFuncDeclaration();
+        fd->type = f->type;
+        return new VarExp(loc, fd, hasOverloads);
+    }
+    if (OverDeclaration *od = s->isOverDeclaration())
+    {
+        e = new VarExp(loc, od, true);
+        e->type = Type::tvoid;
+        return e;
+    }
+    if (OverloadSet *o = s->isOverloadSet())
+    {
+        //printf("'%s' is an overload set\n", o->toChars());
+        return new OverExp(loc, o);
+    }
+
+    if (Import *imp = s->isImport())
+    {
+        if (!imp->pkg)
+        {
+            ::error(loc, "forward reference of import %s", imp->toChars());
+            return new ErrorExp();
+        }
+        ScopeExp *ie = new ScopeExp(loc, imp->pkg);
+        return semantic(ie, sc);
+    }
+    if (Package *pkg = s->isPackage())
+    {
+        ScopeExp *ie = new ScopeExp(loc, pkg);
+        return semantic(ie, sc);
+    }
+    if (Module *mod = s->isModule())
+    {
+        ScopeExp *ie = new ScopeExp(loc, mod);
+        return semantic(ie, sc);
+    }
+
+    if (Nspace *ns = s->isNspace())
+    {
+        ScopeExp *ie = new ScopeExp(loc, ns);
+        return semantic(ie, sc);
+    }
+
+    if (Type *t = s->getType())
+    {
+        TypeExp *te = new TypeExp(loc, t);
+        return semantic(te, sc);
+    }
+
+    if (TupleDeclaration *tup = s->isTupleDeclaration())
+    {
+        if (tup->needThis() && hasThis(sc))
+            e = new DotVarExp(loc, new ThisExp(loc), tup);
+        else
+            e = new TupleExp(loc, tup);
+        e = semantic(e, sc);
+        return e;
+    }
+
+    if (TemplateInstance *ti = s->isTemplateInstance())
+    {
+        ti->semantic(sc);
+        if (!ti->inst || ti->errors)
+            return new ErrorExp();
+        s = ti->toAlias();
+        if (!s->isTemplateInstance())
+            goto Lagain;
+        e = new ScopeExp(loc, ti);
+        e = semantic(e, sc);
+        return e;
+    }
+    if (TemplateDeclaration *td = s->isTemplateDeclaration())
+    {
+        Dsymbol *p = td->toParent2();
+        FuncDeclaration *fdthis = hasThis(sc);
+        AggregateDeclaration *ad = p ? p->isAggregateDeclaration() : NULL;
+        if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad &&
+            (td->_scope->stc & STCstatic) == 0)
+        {
+            e = new DotTemplateExp(loc, new ThisExp(loc), td);
+        }
+        else
+            e = new TemplateExp(loc, td);
+        e = semantic(e, sc);
+        return e;
+    }
+
+    ::error(loc, "%s '%s' is not a variable", s->kind(), s->toChars());
+    return new ErrorExp();
+}
+
+bool DsymbolExp::isLvalue()
+{
+    return true;
+}
+
+Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e)
+{
+    return this;
+}
+
+/******************************** ThisExp **************************/
+
+ThisExp::ThisExp(Loc loc)
+        : Expression(loc, TOKthis, sizeof(ThisExp))
+{
+    //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
+    var = NULL;
+}
+
+bool ThisExp::isBool(bool result)
+{
+    return result ? true : false;
+}
+
+bool ThisExp::isLvalue()
+{
+    // Class `this` should be an rvalue; struct `this` should be an lvalue.
+    return type->toBasetype()->ty != Tclass;
+}
+
+Expression *ThisExp::toLvalue(Scope *sc, Expression *e)
+{
+    if (type->toBasetype()->ty == Tclass)
+    {
+        // Class `this` is an rvalue; struct `this` is an lvalue.
+        return Expression::toLvalue(sc, e);
+    }
+    return this;
+}
+
+/******************************** SuperExp **************************/
+
+SuperExp::SuperExp(Loc loc)
+        : ThisExp(loc)
+{
+    op = TOKsuper;
+}
+
+/******************************** NullExp **************************/
+
+NullExp::NullExp(Loc loc, Type *type)
+        : Expression(loc, TOKnull, sizeof(NullExp))
+{
+    committed = 0;
+    this->type = type;
+}
+
+bool NullExp::equals(RootObject *o)
+{
+    if (o && o->dyncast() == DYNCAST_EXPRESSION)
+    {
+        Expression *e = (Expression *)o;
+        if (e->op == TOKnull &&
+            type->equals(e->type))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool NullExp::isBool(bool result)
+{
+    return result ? false : true;
+}
+
+StringExp *NullExp::toStringExp()
+{
+    if (implicitConvTo(Type::tstring))
+    {
+        StringExp *se = new StringExp(loc, (char*)mem.xcalloc(1, 1), 0);
+        se->type = Type::tstring;
+        return se;
+    }
+    return NULL;
+}
+
+/******************************** StringExp **************************/
+
+StringExp::StringExp(Loc loc, char *string)
+        : Expression(loc, TOKstring, sizeof(StringExp))
+{
+    this->string = string;
+    this->len = strlen(string);
+    this->sz = 1;
+    this->committed = 0;
+    this->postfix = 0;
+    this->ownedByCtfe = OWNEDcode;
+}
+
+StringExp::StringExp(Loc loc, void *string, size_t len)
+        : Expression(loc, TOKstring, sizeof(StringExp))
+{
+    this->string = string;
+    this->len = len;
+    this->sz = 1;
+    this->committed = 0;
+    this->postfix = 0;
+    this->ownedByCtfe = OWNEDcode;
+}
+
+StringExp::StringExp(Loc loc, void *string, size_t len, utf8_t postfix)
+        : Expression(loc, TOKstring, sizeof(StringExp))
+{
+    this->string = string;
+    this->len = len;
+    this->sz = 1;
+    this->committed = 0;
+    this->postfix = postfix;
+    this->ownedByCtfe = OWNEDcode;
+}
+
+StringExp *StringExp::create(Loc loc, char *s)
+{
+    return new StringExp(loc, s);
+}
+
+StringExp *StringExp::create(Loc loc, void *string, size_t len)
+{
+    return new StringExp(loc, string, len);
+}
+
+bool StringExp::equals(RootObject *o)
+{
+    //printf("StringExp::equals('%s') %s\n", o->toChars(), toChars());
+    if (o && o->dyncast() == DYNCAST_EXPRESSION)
+    {
+        Expression *e = (Expression *)o;
+        if (e->op == TOKstring)
+        {
+            return compare(o) == 0;
+        }
+    }
+    return false;
+}
+
+/**********************************
+ * Return the number of code units the string would be if it were re-encoded
+ * as tynto.
+ * Params:
+ *      tynto = code unit type of the target encoding
+ * Returns:
+ *      number of code units
+ */
+
+size_t StringExp::numberOfCodeUnits(int tynto) const
+{
+    int encSize;
+    switch (tynto)
+    {
+        case 0:      return len;
+        case Tchar:  encSize = 1; break;
+        case Twchar: encSize = 2; break;
+        case Tdchar: encSize = 4; break;
+        default:
+            assert(0);
+    }
+    if (sz == encSize)
+        return len;
+
+    size_t result = 0;
+    dchar_t c;
+
+    switch (sz)
+    {
+        case 1:
+            for (size_t u = 0; u < len;)
+            {
+                if (const char *p = utf_decodeChar((utf8_t *)string, len, &u, &c))
+                {
+                    error("%s", p);
+                    return 0;
+                }
+                result += utf_codeLength(encSize, c);
+            }
+            break;
+
+        case 2:
+            for (size_t u = 0; u < len;)
+            {
+                if (const char *p = utf_decodeWchar((utf16_t *)string, len, &u, &c))
+                {
+                    error("%s", p);
+                    return 0;
+                }
+                result += utf_codeLength(encSize, c);
+            }
+            break;
+
+        case 4:
+            for (size_t u = 0; u < len;)
+            {
+                c = *((utf32_t *)((char *)string + u));
+                u += 4;
+                result += utf_codeLength(encSize, c);
+            }
+            break;
+
+        default:
+            assert(0);
+    }
+    return result;
+}
+
+/**********************************************
+ * Write the contents of the string to dest.
+ * Use numberOfCodeUnits() to determine size of result.
+ * Params:
+ *  dest = destination
+ *  tyto = encoding type of the result
+ *  zero = add terminating 0
+ */
+void StringExp::writeTo(void* dest, bool zero, int tyto) const
+{
+    int encSize;
+    switch (tyto)
+    {
+        case 0:      encSize = sz; break;
+        case Tchar:  encSize = 1; break;
+        case Twchar: encSize = 2; break;
+        case Tdchar: encSize = 4; break;
+        default:
+            assert(0);
+    }
+    if (sz == encSize)
+    {
+        memcpy(dest, string, len * sz);
+        if (zero)
+            memset((char *)dest + len * sz, 0, sz);
+    }
+    else
+        assert(0);
+}
+
+/**************************************************
+ * If the string data is UTF-8 and can be accessed directly,
+ * return a pointer to it.
+ * Do not assume a terminating 0.
+ * Returns:
+ *  pointer to string data if possible, null if not
+ */
+char *StringExp::toPtr()
+{
+    return (sz == 1) ? (char*)string : NULL;
+}
+
+StringExp *StringExp::toStringExp()
+{
+    return this;
+}
+
+/****************************************
+ * Convert string to char[].
+ */
+
+StringExp *StringExp::toUTF8(Scope *sc)
+{
+    if (sz != 1)
+    {   // Convert to UTF-8 string
+        committed = 0;
+        Expression *e = castTo(sc, Type::tchar->arrayOf());
+        e = e->optimize(WANTvalue);
+        assert(e->op == TOKstring);
+        StringExp *se = (StringExp *)e;
+        assert(se->sz == 1);
+        return se;
+    }
+    return this;
+}
+
+int StringExp::compare(RootObject *obj)
+{
+    //printf("StringExp::compare()\n");
+    // Used to sort case statement expressions so we can do an efficient lookup
+    StringExp *se2 = (StringExp *)(obj);
+
+    // This is a kludge so isExpression() in template.c will return 5
+    // for StringExp's.
+    if (!se2)
+        return 5;
+
+    assert(se2->op == TOKstring);
+
+    size_t len1 = len;
+    size_t len2 = se2->len;
+
+    //printf("sz = %d, len1 = %d, len2 = %d\n", sz, (int)len1, (int)len2);
+    if (len1 == len2)
+    {
+        switch (sz)
+        {
+            case 1:
+                return memcmp((char *)string, (char *)se2->string, len1);
+
+            case 2:
+            {
+                d_uns16 *s1 = (d_uns16 *)string;
+                d_uns16 *s2 = (d_uns16 *)se2->string;
+
+                for (size_t u = 0; u < len; u++)
+                {
+                    if (s1[u] != s2[u])
+                        return s1[u] - s2[u];
+                }
+            }
+
+            case 4:
+            {
+                d_uns32 *s1 = (d_uns32 *)string;
+                d_uns32 *s2 = (d_uns32 *)se2->string;
+
+                for (size_t u = 0; u < len; u++)
+                {
+                    if (s1[u] != s2[u])
+                        return s1[u] - s2[u];
+                }
+            }
+            break;
+
+            default:
+                assert(0);
+        }
+    }
+    return (int)(len1 - len2);
+}
+
+bool StringExp::isBool(bool result)
+{
+    return result ? true : false;
+}
+
+
+bool StringExp::isLvalue()
+{
+    /* string literal is rvalue in default, but
+     * conversion to reference of static array is only allowed.
+     */
+    return (type && type->toBasetype()->ty == Tsarray);
+}
+
+Expression *StringExp::toLvalue(Scope *sc, Expression *e)
+{
+    //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type->toChars() : NULL);
+    return (type && type->toBasetype()->ty == Tsarray)
+            ? this : Expression::toLvalue(sc, e);
+}
+
+Expression *StringExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    error("cannot modify string literal %s", toChars());
+    return new ErrorExp();
+}
+
+unsigned StringExp::charAt(uinteger_t i) const
+{   unsigned value;
+
+    switch (sz)
+    {
+        case 1:
+            value = ((utf8_t *)string)[(size_t)i];
+            break;
+
+        case 2:
+            value = ((unsigned short *)string)[(size_t)i];
+            break;
+
+        case 4:
+            value = ((unsigned int *)string)[(size_t)i];
+            break;
+
+        default:
+            assert(0);
+            break;
+    }
+    return value;
+}
+
+/************************ ArrayLiteralExp ************************************/
+
+// [ e1, e2, e3, ... ]
+
+ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements)
+    : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
+{
+    this->basis = NULL;
+    this->elements = elements;
+    this->ownedByCtfe = OWNEDcode;
+}
+
+ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e)
+    : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
+{
+    this->basis = NULL;
+    elements = new Expressions;
+    elements->push(e);
+    this->ownedByCtfe = OWNEDcode;
+}
+
+ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *basis, Expressions *elements)
+    : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
+{
+    this->basis = basis;
+    this->elements = elements;
+    this->ownedByCtfe = OWNEDcode;
+}
+
+ArrayLiteralExp *ArrayLiteralExp::create(Loc loc, Expressions *elements)
+{
+    return new ArrayLiteralExp(loc, elements);
+}
+
+bool ArrayLiteralExp::equals(RootObject *o)
+{
+    if (this == o)
+        return true;
+    if (o && o->dyncast() == DYNCAST_EXPRESSION &&
+        ((Expression *)o)->op == TOKarrayliteral)
+    {
+        ArrayLiteralExp *ae = (ArrayLiteralExp *)o;
+        if (elements->dim != ae->elements->dim)
+            return false;
+        if (elements->dim == 0 &&
+            !type->equals(ae->type))
+        {
+            return false;
+        }
+        for (size_t i = 0; i < elements->dim; i++)
+        {
+            Expression *e1 = (*elements)[i];
+            Expression *e2 = (*ae->elements)[i];
+            if (!e1)
+                e1 = basis;
+            if (!e2)
+                e2 = basis;
+            if (e1 != e2 &&
+                (!e1 || !e2 || !e1->equals(e2)))
+                return false;
+        }
+        return true;
+    }
+    return false;
+}
+
+Expression *ArrayLiteralExp::syntaxCopy()
+{
+    return new ArrayLiteralExp(loc,
+        basis ? basis->syntaxCopy() : NULL,
+        arraySyntaxCopy(elements));
+}
+
+Expression *ArrayLiteralExp::getElement(d_size_t i)
+{
+    Expression *el = (*elements)[i];
+    if (!el)
+        el = basis;
+    return el;
+}
+
+static void appendArrayLiteral(Expressions *elems, ArrayLiteralExp *ale)
+{
+    if (!ale->elements)
+        return;
+    size_t d = elems->dim;
+    elems->append(ale->elements);
+    for (size_t i = d; i < elems->dim; i++)
+    {
+        Expression *el = (*elems)[i];
+        if (!el)
+            (*elems)[i] = ale->basis;
+    }
+}
+
+/* Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s.
+ * Params:
+ *      e1  = If it's ArrayLiteralExp, its `elements` will be copied.
+ *            Otherwise, `e1` itself will be pushed into the new `Expressions`.
+ *      e2  = If it's not `null`, it will be pushed/appended to the new
+ *            `Expressions` by the same way with `e1`.
+ * Returns:
+ *      Newly allocated `Expressions`. Note that it points to the original
+ *      `Expression` values in e1 and e2.
+ */
+Expressions* ArrayLiteralExp::copyElements(Expression *e1, Expression *e2)
+{
+    Expressions *elems = new Expressions();
+
+    if (e1->op == TOKarrayliteral)
+        appendArrayLiteral(elems, (ArrayLiteralExp *)e1);
+    else
+        elems->push(e1);
+
+    if (e2)
+    {
+        if (e2->op == TOKarrayliteral)
+            appendArrayLiteral(elems, (ArrayLiteralExp *)e2);
+        else
+            elems->push(e2);
+    }
+
+    return elems;
+}
+
+bool ArrayLiteralExp::isBool(bool result)
+{
+    size_t dim = elements ? elements->dim : 0;
+    return result ? (dim != 0) : (dim == 0);
+}
+
+StringExp *ArrayLiteralExp::toStringExp()
+{
+    TY telem = type->nextOf()->toBasetype()->ty;
+
+    if (telem == Tchar || telem == Twchar || telem == Tdchar ||
+        (telem == Tvoid && (!elements || elements->dim == 0)))
+    {
+        unsigned char sz = 1;
+        if (telem == Twchar) sz = 2;
+        else if (telem == Tdchar) sz = 4;
+
+        OutBuffer buf;
+        if (elements)
+        {
+            for (size_t i = 0; i < elements->dim; ++i)
+            {
+                Expression *ch = getElement(i);
+                if (ch->op != TOKint64)
+                    return NULL;
+                if (sz == 1)
+                    buf.writeByte((unsigned)ch->toInteger());
+                else if (sz == 2)
+                    buf.writeword((unsigned)ch->toInteger());
+                else
+                    buf.write4((unsigned)ch->toInteger());
+            }
+        }
+        char prefix;
+             if (sz == 1) { prefix = 'c'; buf.writeByte(0); }
+        else if (sz == 2) { prefix = 'w'; buf.writeword(0); }
+        else              { prefix = 'd'; buf.write4(0); }
+
+        const size_t len = buf.offset / sz - 1;
+        StringExp *se = new StringExp(loc, buf.extractData(), len, prefix);
+        se->sz = sz;
+        se->type = type;
+        return se;
+    }
+    return NULL;
+}
+
+/************************ AssocArrayLiteralExp ************************************/
+
+// [ key0 : value0, key1 : value1, ... ]
+
+AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc,
+                Expressions *keys, Expressions *values)
+    : Expression(loc, TOKassocarrayliteral, sizeof(AssocArrayLiteralExp))
+{
+    assert(keys->dim == values->dim);
+    this->keys = keys;
+    this->values = values;
+    this->ownedByCtfe = OWNEDcode;
+}
+
+bool AssocArrayLiteralExp::equals(RootObject *o)
+{
+    if (this == o)
+        return true;
+    if (o && o->dyncast() == DYNCAST_EXPRESSION &&
+        ((Expression *)o)->op == TOKassocarrayliteral)
+    {
+        AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)o;
+        if (keys->dim != ae->keys->dim)
+            return false;
+        size_t count = 0;
+        for (size_t i = 0; i < keys->dim; i++)
+        {
+            for (size_t j = 0; j < ae->keys->dim; j++)
+            {
+                if ((*keys)[i]->equals((*ae->keys)[j]))
+                {
+                    if (!(*values)[i]->equals((*ae->values)[j]))
+                        return false;
+                    ++count;
+                }
+            }
+        }
+        return count == keys->dim;
+    }
+    return false;
+}
+
+Expression *AssocArrayLiteralExp::syntaxCopy()
+{
+    return new AssocArrayLiteralExp(loc,
+        arraySyntaxCopy(keys), arraySyntaxCopy(values));
+}
+
+bool AssocArrayLiteralExp::isBool(bool result)
+{
+    size_t dim = keys->dim;
+    return result ? (dim != 0) : (dim == 0);
+}
+
+/************************ StructLiteralExp ************************************/
+
+// sd( e1, e2, e3, ... )
+
+StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype)
+    : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp))
+{
+    this->sd = sd;
+    if (!elements)
+        elements = new Expressions();
+    this->elements = elements;
+    this->stype = stype;
+    this->useStaticInit = false;
+    this->sym = NULL;
+    this->ownedByCtfe = OWNEDcode;
+    this->origin = this;
+    this->stageflags = 0;
+    this->inlinecopy = NULL;
+    //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
+}
+
+StructLiteralExp *StructLiteralExp::create(Loc loc, StructDeclaration *sd, void *elements, Type *stype)
+{
+    return new StructLiteralExp(loc, sd, (Expressions *)elements, stype);
+}
+
+bool StructLiteralExp::equals(RootObject *o)
+{
+    if (this == o)
+        return true;
+    if (o && o->dyncast() == DYNCAST_EXPRESSION &&
+        ((Expression *)o)->op == TOKstructliteral)
+    {
+        StructLiteralExp *se = (StructLiteralExp *)o;
+        if (!type->equals(se->type))
+            return false;
+        if (elements->dim != se->elements->dim)
+            return false;
+        for (size_t i = 0; i < elements->dim; i++)
+        {
+            Expression *e1 = (*elements)[i];
+            Expression *e2 = (*se->elements)[i];
+            if (e1 != e2 &&
+                (!e1 || !e2 || !e1->equals(e2)))
+                return false;
+        }
+        return true;
+    }
+    return false;
+}
+
+Expression *StructLiteralExp::syntaxCopy()
+{
+    StructLiteralExp *exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
+    exp->origin = this;
+    return exp;
+}
+
+Expression *StructLiteralExp::addDtorHook(Scope *sc)
+{
+    /* If struct requires a destructor, rewrite as:
+     *    (S tmp = S()),tmp
+     * so that the destructor can be hung on tmp.
+     */
+    if (sd->dtor && sc->func)
+    {
+        /* Make an identifier for the temporary of the form:
+         *   __sl%s%d, where %s is the struct name
+         */
+        const size_t len = 10;
+        char buf[len + 1];
+        buf[len] = 0;
+        strcpy(buf, "__sl");
+        strncat(buf, sd->ident->toChars(), len - 4 - 1);
+        assert(buf[len] == 0);
+
+        VarDeclaration *tmp = copyToTemp(0, buf, this);
+        Expression *ae = new DeclarationExp(loc, tmp);
+        Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp));
+        e = semantic(e, sc);
+        return e;
+    }
+    return this;
+}
+
+/**************************************
+ * Gets expression at offset of type.
+ * Returns NULL if not found.
+ */
+
+Expression *StructLiteralExp::getField(Type *type, unsigned offset)
+{
+    //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
+    //  /*toChars()*/"", type->toChars(), offset);
+    Expression *e = NULL;
+    int i = getFieldIndex(type, offset);
+
+    if (i != -1)
+    {
+        //printf("\ti = %d\n", i);
+        if (i == sd->fields.dim - 1 && sd->isNested())
+            return NULL;
+
+        assert(i < elements->dim);
+        e = (*elements)[i];
+        if (e)
+        {
+            //printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars());
+
+            /* If type is a static array, and e is an initializer for that array,
+             * then the field initializer should be an array literal of e.
+             */
+            if (e->type->castMod(0) != type->castMod(0) && type->ty == Tsarray)
+            {   TypeSArray *tsa = (TypeSArray *)type;
+                size_t length = (size_t)tsa->dim->toInteger();
+                Expressions *z = new Expressions;
+                z->setDim(length);
+                for (size_t q = 0; q < length; ++q)
+                    (*z)[q] = e->copy();
+                e = new ArrayLiteralExp(loc, z);
+                e->type = type;
+            }
+            else
+            {
+                e = e->copy();
+                e->type = type;
+            }
+            if (useStaticInit && e->op == TOKstructliteral &&
+                e->type->needsNested())
+            {
+                StructLiteralExp *se = (StructLiteralExp *)e;
+                se->useStaticInit = true;
+            }
+        }
+    }
+    return e;
+}
+
+/************************************
+ * Get index of field.
+ * Returns -1 if not found.
+ */
+
+int StructLiteralExp::getFieldIndex(Type *type, unsigned offset)
+{
+    /* Find which field offset is by looking at the field offsets
+     */
+    if (elements->dim)
+    {
+        for (size_t i = 0; i < sd->fields.dim; i++)
+        {
+            VarDeclaration *v = sd->fields[i];
+
+            if (offset == v->offset &&
+                type->size() == v->type->size())
+            {
+                /* context field might not be filled. */
+                if (i == sd->fields.dim - 1 && sd->isNested())
+                    return (int)i;
+                Expression *e = (*elements)[i];
+                if (e)
+                {
+                    return (int)i;
+                }
+                break;
+            }
+        }
+    }
+    return -1;
+}
+
+/************************ TypeDotIdExp ************************************/
+
+/* Things like:
+ *      int.size
+ *      foo.size
+ *      (foo).size
+ *      cast(foo).size
+ */
+
+DotIdExp *typeDotIdExp(Loc loc, Type *type, Identifier *ident)
+{
+    return new DotIdExp(loc, new TypeExp(loc, type), ident);
+}
+
+
+/************************************************************/
+
+// Mainly just a placeholder
+
+TypeExp::TypeExp(Loc loc, Type *type)
+    : Expression(loc, TOKtype, sizeof(TypeExp))
+{
+    //printf("TypeExp::TypeExp(%s)\n", type->toChars());
+    this->type = type;
+}
+
+Expression *TypeExp::syntaxCopy()
+{
+    return new TypeExp(loc, type->syntaxCopy());
+}
+
+bool TypeExp::checkType()
+{
+    error("type %s is not an expression", toChars());
+    return true;
+}
+
+bool TypeExp::checkValue()
+{
+    error("type %s has no value", toChars());
+    return true;
+}
+
+/************************************************************/
+
+// Mainly just a placeholder
+
+ScopeExp::ScopeExp(Loc loc, ScopeDsymbol *sds)
+    : Expression(loc, TOKscope, sizeof(ScopeExp))
+{
+    //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds->toChars());
+    //static int count; if (++count == 38) *(char*)0=0;
+    this->sds = sds;
+}
+
+Expression *ScopeExp::syntaxCopy()
+{
+    return new ScopeExp(loc, (ScopeDsymbol *)sds->syntaxCopy(NULL));
+}
+
+bool ScopeExp::checkType()
+{
+    if (sds->isPackage())
+    {
+        error("%s %s has no type", sds->kind(), sds->toChars());
+        return true;
+    }
+    if (TemplateInstance *ti = sds->isTemplateInstance())
+    {
+        //assert(ti->needsTypeInference(sc));
+        if (ti->tempdecl &&
+            ti->semantictiargsdone &&
+            ti->semanticRun == PASSinit)
+        {
+            error("partial %s %s has no type", sds->kind(), toChars());
+            return true;
+        }
+    }
+    return false;
+}
+
+bool ScopeExp::checkValue()
+{
+    error("%s %s has no value", sds->kind(), sds->toChars());
+    return true;
+}
+
+/********************** TemplateExp **************************************/
+
+// Mainly just a placeholder
+
+TemplateExp::TemplateExp(Loc loc, TemplateDeclaration *td, FuncDeclaration *fd)
+    : Expression(loc, TOKtemplate, sizeof(TemplateExp))
+{
+    //printf("TemplateExp(): %s\n", td->toChars());
+    this->td = td;
+    this->fd = fd;
+}
+
+bool TemplateExp::checkType()
+{
+    error("%s %s has no type", td->kind(), toChars());
+    return true;
+}
+
+bool TemplateExp::checkValue()
+{
+    error("%s %s has no value", td->kind(), toChars());
+    return true;
+}
+
+bool TemplateExp::isLvalue()
+{
+    return fd != NULL;
+}
+
+Expression *TemplateExp::toLvalue(Scope *sc, Expression *e)
+{
+    if (!fd)
+        return Expression::toLvalue(sc, e);
+
+    assert(sc);
+    return resolve(loc, sc, fd, true);
+}
+
+/********************** NewExp **************************************/
+
+/* thisexp.new(newargs) newtype(arguments) */
+
+NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs,
+        Type *newtype, Expressions *arguments)
+    : Expression(loc, TOKnew, sizeof(NewExp))
+{
+    this->thisexp = thisexp;
+    this->newargs = newargs;
+    this->newtype = newtype;
+    this->arguments = arguments;
+    argprefix = NULL;
+    member = NULL;
+    allocator = NULL;
+    onstack = 0;
+}
+
+NewExp *NewExp::create(Loc loc, Expression *thisexp, Expressions *newargs,
+        Type *newtype, Expressions *arguments)
+{
+    return new NewExp(loc, thisexp, newargs, newtype, arguments);
+}
+
+Expression *NewExp::syntaxCopy()
+{
+    return new NewExp(loc,
+        thisexp ? thisexp->syntaxCopy() : NULL,
+        arraySyntaxCopy(newargs),
+        newtype->syntaxCopy(), arraySyntaxCopy(arguments));
+}
+
+/********************** NewAnonClassExp **************************************/
+
+NewAnonClassExp::NewAnonClassExp(Loc loc, Expression *thisexp,
+        Expressions *newargs, ClassDeclaration *cd, Expressions *arguments)
+    : Expression(loc, TOKnewanonclass, sizeof(NewAnonClassExp))
+{
+    this->thisexp = thisexp;
+    this->newargs = newargs;
+    this->cd = cd;
+    this->arguments = arguments;
+}
+
+Expression *NewAnonClassExp::syntaxCopy()
+{
+    return new NewAnonClassExp(loc,
+        thisexp ? thisexp->syntaxCopy() : NULL,
+        arraySyntaxCopy(newargs),
+        (ClassDeclaration *)cd->syntaxCopy(NULL),
+        arraySyntaxCopy(arguments));
+}
+
+/********************** SymbolExp **************************************/
+
+SymbolExp::SymbolExp(Loc loc, TOK op, int size, Declaration *var, bool hasOverloads)
+    : Expression(loc, op, size)
+{
+    assert(var);
+    this->var = var;
+    this->hasOverloads = hasOverloads;
+}
+
+/********************** SymOffExp **************************************/
+
+SymOffExp::SymOffExp(Loc loc, Declaration *var, dinteger_t offset, bool hasOverloads)
+    : SymbolExp(loc, TOKsymoff, sizeof(SymOffExp), var,
+                var->isVarDeclaration() ? false : hasOverloads)
+{
+    if (VarDeclaration *v = var->isVarDeclaration())
+    {
+        // FIXME: This error report will never be handled anyone.
+        // It should be done before the SymOffExp construction.
+        if (v->needThis())
+            ::error(loc, "need 'this' for address of %s", v->toChars());
+    }
+    this->offset = offset;
+}
+
+bool SymOffExp::isBool(bool result)
+{
+    return result ? true : false;
+}
+
+/******************************** VarExp **************************/
+
+VarExp::VarExp(Loc loc, Declaration *var, bool hasOverloads)
+    : SymbolExp(loc, TOKvar, sizeof(VarExp), var,
+                var->isVarDeclaration() ? false : hasOverloads)
+{
+    //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var->toChars(), loc.toChars());
+    //if (strcmp(var->ident->toChars(), "func") == 0) halt();
+    this->type = var->type;
+}
+
+VarExp *VarExp::create(Loc loc, Declaration *var, bool hasOverloads)
+{
+    return new VarExp(loc, var, hasOverloads);
+}
+
+bool VarExp::equals(RootObject *o)
+{
+    if (this == o)
+        return true;
+    if (((Expression *)o)->op == TOKvar)
+    {
+        VarExp *ne = (VarExp *)o;
+        if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
+            var == ne->var)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool VarExp::isLvalue()
+{
+    if (var->storage_class & (STClazy | STCrvalue | STCmanifest))
+        return false;
+    return true;
+}
+
+Expression *VarExp::toLvalue(Scope *sc, Expression *e)
+{
+    if (var->storage_class & STCmanifest)
+    {
+        error("manifest constant '%s' is not lvalue", var->toChars());
+        return new ErrorExp();
+    }
+    if (var->storage_class & STClazy)
+    {
+        error("lazy variables cannot be lvalues");
+        return new ErrorExp();
+    }
+    if (var->ident == Id::ctfe)
+    {
+        error("compiler-generated variable __ctfe is not an lvalue");
+        return new ErrorExp();
+    }
+    if (var->ident == Id::dollar)   // Bugzilla 13574
+    {
+        error("'$' is not an lvalue");
+        return new ErrorExp();
+    }
+    return this;
+}
+
+int VarExp::checkModifiable(Scope *sc, int flag)
+{
+    //printf("VarExp::checkModifiable %s", toChars());
+    assert(type);
+    return var->checkModify(loc, sc, type, NULL, flag);
+}
+
+Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    //printf("VarExp::modifiableLvalue('%s')\n", var->toChars());
+    if (var->storage_class & STCmanifest)
+    {
+        error("cannot modify manifest constant '%s'", toChars());
+        return new ErrorExp();
+    }
+    // See if this expression is a modifiable lvalue (i.e. not const)
+    return Expression::modifiableLvalue(sc, e);
+}
+
+
+/******************************** OverExp **************************/
+
+OverExp::OverExp(Loc loc, OverloadSet *s)
+        : Expression(loc, TOKoverloadset, sizeof(OverExp))
+{
+    //printf("OverExp(this = %p, '%s')\n", this, var->toChars());
+    vars = s;
+    type = Type::tvoid;
+}
+
+bool OverExp::isLvalue()
+{
+    return true;
+}
+
+Expression *OverExp::toLvalue(Scope *sc, Expression *e)
+{
+    return this;
+}
+
+/******************************** TupleExp **************************/
+
+TupleExp::TupleExp(Loc loc, Expression *e0, Expressions *exps)
+        : Expression(loc, TOKtuple, sizeof(TupleExp))
+{
+    //printf("TupleExp(this = %p)\n", this);
+    this->e0 = e0;
+    this->exps = exps;
+}
+
+TupleExp::TupleExp(Loc loc, Expressions *exps)
+        : Expression(loc, TOKtuple, sizeof(TupleExp))
+{
+    //printf("TupleExp(this = %p)\n", this);
+    this->e0 = NULL;
+    this->exps = exps;
+}
+
+TupleExp::TupleExp(Loc loc, TupleDeclaration *tup)
+        : Expression(loc, TOKtuple, sizeof(TupleExp))
+{
+    this->e0 = NULL;
+    this->exps = new Expressions();
+
+    this->exps->reserve(tup->objects->dim);
+    for (size_t i = 0; i < tup->objects->dim; i++)
+    {   RootObject *o = (*tup->objects)[i];
+        if (Dsymbol *s = getDsymbol(o))
+        {
+            /* If tuple element represents a symbol, translate to DsymbolExp
+             * to supply implicit 'this' if needed later.
+             */
+            Expression *e = new DsymbolExp(loc, s);
+            this->exps->push(e);
+        }
+        else if (o->dyncast() == DYNCAST_EXPRESSION)
+        {
+            Expression *e = (Expression *)o;
+            this->exps->push(e);
+        }
+        else if (o->dyncast() == DYNCAST_TYPE)
+        {
+            Type *t = (Type *)o;
+            Expression *e = new TypeExp(loc, t);
+            this->exps->push(e);
+        }
+        else
+        {
+            error("%s is not an expression", o->toChars());
+        }
+    }
+}
+
+bool TupleExp::equals(RootObject *o)
+{
+    if (this == o)
+        return true;
+    if (((Expression *)o)->op == TOKtuple)
+    {
+        TupleExp *te = (TupleExp *)o;
+        if (exps->dim != te->exps->dim)
+            return false;
+        if (e0 && !e0->equals(te->e0) || !e0 && te->e0)
+            return false;
+        for (size_t i = 0; i < exps->dim; i++)
+        {
+            Expression *e1 = (*exps)[i];
+            Expression *e2 = (*te->exps)[i];
+            if (!e1->equals(e2))
+                return false;
+        }
+        return true;
+    }
+    return false;
+}
+
+Expression *TupleExp::syntaxCopy()
+{
+    return new TupleExp(loc, e0 ? e0->syntaxCopy() : NULL, arraySyntaxCopy(exps));
+}
+
+/******************************** FuncExp *********************************/
+
+FuncExp::FuncExp(Loc loc, Dsymbol *s)
+        : Expression(loc, TOKfunction, sizeof(FuncExp))
+{
+    this->td = s->isTemplateDeclaration();
+    this->fd = s->isFuncLiteralDeclaration();
+    if (td)
+    {
+        assert(td->literal);
+        assert(td->members && td->members->dim == 1);
+        fd = (*td->members)[0]->isFuncLiteralDeclaration();
+    }
+    tok = fd->tok;  // save original kind of function/delegate/(infer)
+    assert(fd->fbody);
+}
+
+bool FuncExp::equals(RootObject *o)
+{
+    if (this == o)
+        return true;
+    if (o->dyncast() != DYNCAST_EXPRESSION)
+        return false;
+    if (((Expression *)o)->op == TOKfunction)
+    {
+        FuncExp *fe = (FuncExp *)o;
+        return fd == fe->fd;
+    }
+    return false;
+}
+
+void FuncExp::genIdent(Scope *sc)
+{
+    if (fd->ident == Id::empty)
+    {
+        const char *s;
+        if (fd->fes)                        s = "__foreachbody";
+        else if (fd->tok == TOKreserved)    s = "__lambda";
+        else if (fd->tok == TOKdelegate)    s = "__dgliteral";
+        else                                s = "__funcliteral";
+
+        DsymbolTable *symtab;
+        if (FuncDeclaration *func = sc->parent->isFuncDeclaration())
+        {
+            if (func->localsymtab == NULL)
+            {
+                // Inside template constraint, symtab is not set yet.
+                // Initialize it lazily.
+                func->localsymtab = new DsymbolTable();
+            }
+            symtab = func->localsymtab;
+        }
+        else
+        {
+            ScopeDsymbol *sds = sc->parent->isScopeDsymbol();
+            if (!sds->symtab)
+            {
+                // Inside template constraint, symtab may not be set yet.
+                // Initialize it lazily.
+                assert(sds->isTemplateInstance());
+                sds->symtab = new DsymbolTable();
+            }
+            symtab = sds->symtab;
+        }
+        assert(symtab);
+        int num = (int)dmd_aaLen(symtab->tab) + 1;
+        Identifier *id = Identifier::generateId(s, num);
+        fd->ident = id;
+        if (td) td->ident = id;
+        symtab->insert(td ? (Dsymbol *)td : (Dsymbol *)fd);
+    }
+}
+
+Expression *FuncExp::syntaxCopy()
+{
+    if (td)
+        return new FuncExp(loc, td->syntaxCopy(NULL));
+    else if (fd->semanticRun == PASSinit)
+        return new FuncExp(loc, fd->syntaxCopy(NULL));
+    else    // Bugzilla 13481: Prevent multiple semantic analysis of lambda body.
+        return new FuncExp(loc, fd);
+}
+
+MATCH FuncExp::matchType(Type *to, Scope *sc, FuncExp **presult, int flag)
+{
+    //printf("FuncExp::matchType('%s'), to=%s\n", type ? type->toChars() : "null", to->toChars());
+    if (presult)
+        *presult = NULL;
+
+    TypeFunction *tof = NULL;
+    if (to->ty == Tdelegate)
+    {
+        if (tok == TOKfunction)
+        {
+            if (!flag)
+                error("cannot match function literal to delegate type '%s'", to->toChars());
+            return MATCHnomatch;
+        }
+        tof = (TypeFunction *)to->nextOf();
+    }
+    else if (to->ty == Tpointer && to->nextOf()->ty == Tfunction)
+    {
+        if (tok == TOKdelegate)
+        {
+            if (!flag)
+                error("cannot match delegate literal to function pointer type '%s'", to->toChars());
+            return MATCHnomatch;
+        }
+        tof = (TypeFunction *)to->nextOf();
+    }
+
+    if (td)
+    {
+        if (!tof)
+        {
+        L1:
+            if (!flag)
+                error("cannot infer parameter types from %s", to->toChars());
+            return MATCHnomatch;
+        }
+
+        // Parameter types inference from 'tof'
+        assert(td->_scope);
+        TypeFunction *tf = (TypeFunction *)fd->type;
+        //printf("\ttof = %s\n", tof->toChars());
+        //printf("\ttf  = %s\n", tf->toChars());
+        size_t dim = Parameter::dim(tf->parameters);
+
+        if (Parameter::dim(tof->parameters) != dim ||
+            tof->varargs != tf->varargs)
+            goto L1;
+
+        Objects *tiargs = new Objects();
+        tiargs->reserve(td->parameters->dim);
+
+        for (size_t i = 0; i < td->parameters->dim; i++)
+        {
+            TemplateParameter *tp = (*td->parameters)[i];
+            size_t u = 0;
+            for (; u < dim; u++)
+            {
+                Parameter *p = Parameter::getNth(tf->parameters, u);
+                if (p->type->ty == Tident &&
+                    ((TypeIdentifier *)p->type)->ident == tp->ident)
+                {
+                    break;
+                }
+            }
+            assert(u < dim);
+            Parameter *pto = Parameter::getNth(tof->parameters, u);
+            Type *t = pto->type;
+            if (t->ty == Terror)
+                goto L1;
+            tiargs->push(t);
+        }
+
+        // Set target of return type inference
+        if (!tf->next && tof->next)
+            fd->treq = to;
+
+        TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
+        Expression *ex = new ScopeExp(loc, ti);
+        ex = ::semantic(ex, td->_scope);
+
+        // Reset inference target for the later re-semantic
+        fd->treq = NULL;
+
+        if (ex->op == TOKerror)
+            return MATCHnomatch;
+        if (ex->op != TOKfunction)
+            goto L1;
+        return ((FuncExp *)ex)->matchType(to, sc, presult, flag);
+    }
+
+    if (!tof || !tof->next)
+        return MATCHnomatch;
+
+    assert(type && type != Type::tvoid);
+    TypeFunction *tfx = (TypeFunction *)fd->type;
+    bool convertMatch = (type->ty != to->ty);
+
+    if (fd->inferRetType && tfx->next->implicitConvTo(tof->next) == MATCHconvert)
+    {
+        /* If return type is inferred and covariant return,
+         * tweak return statements to required return type.
+         *
+         * interface I {}
+         * class C : Object, I{}
+         *
+         * I delegate() dg = delegate() { return new class C(); }
+         */
+        convertMatch = true;
+
+        TypeFunction *tfy = new TypeFunction(tfx->parameters, tof->next, tfx->varargs, tfx->linkage, STCundefined);
+        tfy->mod = tfx->mod;
+        tfy->isnothrow  = tfx->isnothrow;
+        tfy->isnogc     = tfx->isnogc;
+        tfy->purity     = tfx->purity;
+        tfy->isproperty = tfx->isproperty;
+        tfy->isref      = tfx->isref;
+        tfy->iswild     = tfx->iswild;
+        tfy->deco = tfy->merge()->deco;
+
+        tfx = tfy;
+    }
+
+    Type *tx;
+    if (tok == TOKdelegate ||
+        tok == TOKreserved && (type->ty == Tdelegate ||
+                               type->ty == Tpointer && to->ty == Tdelegate))
+    {
+        // Allow conversion from implicit function pointer to delegate
+        tx = new TypeDelegate(tfx);
+        tx->deco = tx->merge()->deco;
+    }
+    else
+    {
+        assert(tok == TOKfunction ||
+               tok == TOKreserved && type->ty == Tpointer);
+        tx = tfx->pointerTo();
+    }
+    //printf("\ttx = %s, to = %s\n", tx->toChars(), to->toChars());
+
+    MATCH m = tx->implicitConvTo(to);
+    if (m > MATCHnomatch)
+    {
+        // MATCHexact:      exact type match
+        // MATCHconst:      covairiant type match (eg. attributes difference)
+        // MATCHconvert:    context conversion
+        m = convertMatch ? MATCHconvert : tx->equals(to) ? MATCHexact : MATCHconst;
+
+        if (presult)
+        {
+            (*presult) = (FuncExp *)copy();
+            (*presult)->type = to;
+
+            // Bugzilla 12508: Tweak function body for covariant returns.
+            (*presult)->fd->modifyReturns(sc, tof->next);
+        }
+    }
+    else if (!flag)
+    {
+        error("cannot implicitly convert expression (%s) of type %s to %s",
+                toChars(), tx->toChars(), to->toChars());
+    }
+    return m;
+}
+
+const char *FuncExp::toChars()
+{
+    return fd->toChars();
+}
+
+bool FuncExp::checkType()
+{
+    if (td)
+    {
+        error("template lambda has no type");
+        return true;
+    }
+    return false;
+}
+
+bool FuncExp::checkValue()
+{
+    if (td)
+    {
+        error("template lambda has no value");
+        return true;
+    }
+    return false;
+}
+
+/******************************** DeclarationExp **************************/
+
+DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration)
+        : Expression(loc, TOKdeclaration, sizeof(DeclarationExp))
+{
+    this->declaration = declaration;
+}
+
+Expression *DeclarationExp::syntaxCopy()
+{
+    return new DeclarationExp(loc, declaration->syntaxCopy(NULL));
+}
+
+bool DeclarationExp::hasCode()
+{
+    if (VarDeclaration *vd = declaration->isVarDeclaration())
+    {
+        return !(vd->storage_class & (STCmanifest | STCstatic));
+    }
+    return false;
+}
+
+/************************ TypeidExp ************************************/
+
+/*
+ *      typeid(int)
+ */
+
+TypeidExp::TypeidExp(Loc loc, RootObject *o)
+    : Expression(loc, TOKtypeid, sizeof(TypeidExp))
+{
+    this->obj = o;
+}
+
+Expression *TypeidExp::syntaxCopy()
+{
+    return new TypeidExp(loc, objectSyntaxCopy(obj));
+}
+
+/************************ TraitsExp ************************************/
+/*
+ *      __traits(identifier, args...)
+ */
+
+TraitsExp::TraitsExp(Loc loc, Identifier *ident, Objects *args)
+    : Expression(loc, TOKtraits, sizeof(TraitsExp))
+{
+    this->ident = ident;
+    this->args = args;
+}
+
+Expression *TraitsExp::syntaxCopy()
+{
+    return new TraitsExp(loc, ident, TemplateInstance::arraySyntaxCopy(args));
+}
+
+/************************************************************/
+
+HaltExp::HaltExp(Loc loc)
+        : Expression(loc, TOKhalt, sizeof(HaltExp))
+{
+}
+
+/************************************************************/
+
+IsExp::IsExp(Loc loc, Type *targ, Identifier *id, TOK tok,
+        Type *tspec, TOK tok2, TemplateParameters *parameters)
+        : Expression(loc, TOKis, sizeof(IsExp))
+{
+    this->targ = targ;
+    this->id = id;
+    this->tok = tok;
+    this->tspec = tspec;
+    this->tok2 = tok2;
+    this->parameters = parameters;
+}
+
+Expression *IsExp::syntaxCopy()
+{
+    // This section is identical to that in TemplateDeclaration::syntaxCopy()
+    TemplateParameters *p = NULL;
+    if (parameters)
+    {
+        p = new TemplateParameters();
+        p->setDim(parameters->dim);
+        for (size_t i = 0; i < p->dim; i++)
+            (*p)[i] = (*parameters)[i]->syntaxCopy();
+    }
+    return new IsExp(loc,
+        targ->syntaxCopy(),
+        id,
+        tok,
+        tspec ? tspec->syntaxCopy() : NULL,
+        tok2,
+        p);
+}
+
+void unSpeculative(Scope *sc, RootObject *o);
+
+/************************************************************/
+
+UnaExp::UnaExp(Loc loc, TOK op, int size, Expression *e1)
+        : Expression(loc, op, size)
+{
+    this->e1 = e1;
+    this->att1 = NULL;
+}
+
+Expression *UnaExp::syntaxCopy()
+{
+    UnaExp *e = (UnaExp *)copy();
+    e->type = NULL;
+    e->e1 = e->e1->syntaxCopy();
+    return e;
+}
+
+/********************************
+ * The type for a unary expression is incompatible.
+ * Print error message.
+ * Returns:
+ *  ErrorExp
+ */
+Expression *UnaExp::incompatibleTypes()
+{
+    if (e1->type->toBasetype() == Type::terror)
+        return e1;
+
+    if (e1->op == TOKtype)
+    {
+        error("incompatible type for (%s(%s)): cannot use '%s' with types",
+              Token::toChars(op), e1->toChars(), Token::toChars(op));
+    }
+    else
+    {
+        error("incompatible type for (%s(%s)): '%s'",
+              Token::toChars(op), e1->toChars(), e1->type->toChars());
+    }
+    return new ErrorExp();
+}
+
+Expression *UnaExp::resolveLoc(Loc loc, Scope *sc)
+{
+    e1 = e1->resolveLoc(loc, sc);
+    return this;
+}
+
+/************************************************************/
+
+BinExp::BinExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2)
+        : Expression(loc, op, size)
+{
+    this->e1 = e1;
+    this->e2 = e2;
+
+    this->att1 = NULL;
+    this->att2 = NULL;
+}
+
+Expression *BinExp::syntaxCopy()
+{
+    BinExp *e = (BinExp *)copy();
+    e->type = NULL;
+    e->e1 = e->e1->syntaxCopy();
+    e->e2 = e->e2->syntaxCopy();
+    return e;
+}
+
+Expression *BinExp::checkOpAssignTypes(Scope *sc)
+{
+    // At that point t1 and t2 are the merged types. type is the original type of the lhs.
+    Type *t1 = e1->type;
+    Type *t2 = e2->type;
+
+    // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
+    // See issue 3841.
+    // Should we also prevent double to float (type->isfloating() && type->size() < t2 ->size()) ?
+    if (op == TOKaddass || op == TOKminass ||
+        op == TOKmulass || op == TOKdivass || op == TOKmodass ||
+        op == TOKpowass)
+    {
+        if ((type->isintegral() && t2->isfloating()))
+        {
+            warning("%s %s %s is performing truncating conversion",
+                    type->toChars(), Token::toChars(op), t2->toChars());
+        }
+    }
+
+    // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
+    if (op == TOKmulass || op == TOKdivass || op == TOKmodass)
+    {
+        // Any multiplication by an imaginary or complex number yields a complex result.
+        // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
+        const char *opstr = Token::toChars(op);
+        if (t1->isreal() && t2->iscomplex())
+        {
+            error("%s %s %s is undefined. Did you mean %s %s %s.re ?",
+                t1->toChars(), opstr, t2->toChars(),
+                t1->toChars(), opstr, t2->toChars());
+            return new ErrorExp();
+        }
+        else if (t1->isimaginary() && t2->iscomplex())
+        {
+            error("%s %s %s is undefined. Did you mean %s %s %s.im ?",
+                t1->toChars(), opstr, t2->toChars(),
+                t1->toChars(), opstr, t2->toChars());
+            return new ErrorExp();
+        }
+        else if ((t1->isreal() || t1->isimaginary()) &&
+            t2->isimaginary())
+        {
+            error("%s %s %s is an undefined operation", t1->toChars(), opstr, t2->toChars());
+            return new ErrorExp();
+        }
+    }
+
+    // generate an error if this is a nonsensical += or -=, eg real += imaginary
+    if (op == TOKaddass || op == TOKminass)
+    {
+        // Addition or subtraction of a real and an imaginary is a complex result.
+        // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
+        if ((t1->isreal() && (t2->isimaginary() || t2->iscomplex())) ||
+            (t1->isimaginary() && (t2->isreal() || t2->iscomplex())))
+        {
+            error("%s %s %s is undefined (result is complex)",
+                t1->toChars(), Token::toChars(op), t2->toChars());
+            return new ErrorExp();
+        }
+        if (type->isreal() || type->isimaginary())
+        {
+            assert(global.errors || t2->isfloating());
+            e2 = e2->castTo(sc, t1);
+        }
+    }
+
+    if (op == TOKmulass)
+    {
+        if (t2->isfloating())
+        {
+            if (t1->isreal())
+            {
+                if (t2->isimaginary() || t2->iscomplex())
+                {
+                    e2 = e2->castTo(sc, t1);
+                }
+            }
+            else if (t1->isimaginary())
+            {
+                if (t2->isimaginary() || t2->iscomplex())
+                {
+                    switch (t1->ty)
+                    {
+                        case Timaginary32: t2 = Type::tfloat32; break;
+                        case Timaginary64: t2 = Type::tfloat64; break;
+                        case Timaginary80: t2 = Type::tfloat80; break;
+                        default:
+                            assert(0);
+                    }
+                    e2 = e2->castTo(sc, t2);
+                }
+            }
+        }
+    }
+    else if (op == TOKdivass)
+    {
+        if (t2->isimaginary())
+        {
+            if (t1->isreal())
+            {
+                // x/iv = i(-x/v)
+                // Therefore, the result is 0
+                e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat::zero, t1));
+                e2->type = t1;
+                Expression *e = new AssignExp(loc, e1, e2);
+                e->type = t1;
+                return e;
+            }
+            else if (t1->isimaginary())
+            {
+                Type *t3;
+                switch (t1->ty)
+                {
+                    case Timaginary32: t3 = Type::tfloat32; break;
+                    case Timaginary64: t3 = Type::tfloat64; break;
+                    case Timaginary80: t3 = Type::tfloat80; break;
+                    default:
+                        assert(0);
+                }
+                e2 = e2->castTo(sc, t3);
+                Expression *e = new AssignExp(loc, e1, e2);
+                e->type = t1;
+                return e;
+            }
+        }
+    }
+    else if (op == TOKmodass)
+    {
+        if (t2->iscomplex())
+        {
+            error("cannot perform modulo complex arithmetic");
+            return new ErrorExp();
+        }
+    }
+    return this;
+}
+
+/********************************
+ * The types for a binary expression are incompatible.
+ * Print error message.
+ * Returns:
+ *  ErrorExp
+ */
+Expression *BinExp::incompatibleTypes()
+{
+    if (e1->type->toBasetype() == Type::terror)
+        return e1;
+    if (e2->type->toBasetype() == Type::terror)
+        return e2;
+
+    // CondExp uses 'a ? b : c' but we're comparing 'b : c'
+    TOK thisOp = (op == TOKquestion) ? TOKcolon : op;
+    if (e1->op == TOKtype || e2->op == TOKtype)
+    {
+        error("incompatible types for ((%s) %s (%s)): cannot use '%s' with types",
+            e1->toChars(), Token::toChars(thisOp), e2->toChars(), Token::toChars(op));
+    }
+    else
+    {
+        error("incompatible types for ((%s) %s (%s)): '%s' and '%s'",
+            e1->toChars(), Token::toChars(thisOp), e2->toChars(),
+            e1->type->toChars(), e2->type->toChars());
+    }
+    return new ErrorExp();
+}
+
+bool BinExp::checkIntegralBin()
+{
+    bool r1 = e1->checkIntegral();
+    bool r2 = e2->checkIntegral();
+    return (r1 || r2);
+}
+
+bool BinExp::checkArithmeticBin()
+{
+    bool r1 = e1->checkArithmetic();
+    bool r2 = e2->checkArithmetic();
+    return (r1 || r2);
+}
+
+/********************** BinAssignExp **************************************/
+
+BinAssignExp::BinAssignExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2)
+        : BinExp(loc, op, size, e1, e2)
+{
+}
+
+bool BinAssignExp::isLvalue()
+{
+    return true;
+}
+
+Expression *BinAssignExp::toLvalue(Scope *sc, Expression *ex)
+{
+    // Lvalue-ness will be handled in glue layer.
+    return this;
+}
+
+Expression *BinAssignExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    // should check e1->checkModifiable() ?
+    return toLvalue(sc, this);
+}
+
+/************************************************************/
+
+CompileExp::CompileExp(Loc loc, Expression *e)
+        : UnaExp(loc, TOKmixin, sizeof(CompileExp), e)
+{
+}
+
+/************************************************************/
+
+ImportExp::ImportExp(Loc loc, Expression *e)
+        : UnaExp(loc, TOKimport, sizeof(ImportExp), e)
+{
+}
+
+/************************************************************/
+
+AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg)
+        : UnaExp(loc, TOKassert, sizeof(AssertExp), e)
+{
+    this->msg = msg;
+}
+
+Expression *AssertExp::syntaxCopy()
+{
+    return new AssertExp(loc, e1->syntaxCopy(), msg ? msg->syntaxCopy() : NULL);
+}
+
+/************************************************************/
+
+DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident)
+        : UnaExp(loc, TOKdotid, sizeof(DotIdExp), e)
+{
+    this->ident = ident;
+    this->wantsym = false;
+}
+
+DotIdExp *DotIdExp::create(Loc loc, Expression *e, Identifier *ident)
+{
+    return new DotIdExp(loc, e, ident);
+}
+
+/********************** DotTemplateExp ***********************************/
+
+// Mainly just a placeholder
+
+DotTemplateExp::DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td)
+        : UnaExp(loc, TOKdottd, sizeof(DotTemplateExp), e)
+
+{
+    this->td = td;
+}
+
+/************************************************************/
+
+DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *var, bool hasOverloads)
+        : UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e)
+{
+    //printf("DotVarExp()\n");
+    this->var = var;
+    this->hasOverloads = var->isVarDeclaration() ? false : hasOverloads;
+}
+
+bool DotVarExp::isLvalue()
+{
+    return true;
+}
+
+Expression *DotVarExp::toLvalue(Scope *sc, Expression *e)
+{
+    //printf("DotVarExp::toLvalue(%s)\n", toChars());
+    return this;
+}
+
+/***********************************************
+ * Mark variable v as modified if it is inside a constructor that var
+ * is a field in.
+ */
+int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1)
+{
+    //printf("modifyFieldVar(var = %s)\n", var->toChars());
+    Dsymbol *s = sc->func;
+    while (1)
+    {
+        FuncDeclaration *fd = NULL;
+        if (s)
+            fd = s->isFuncDeclaration();
+        if (fd &&
+            ((fd->isCtorDeclaration() && var->isField()) ||
+             (fd->isStaticCtorDeclaration() && !var->isField())) &&
+            fd->toParent2() == var->toParent2() &&
+            (!e1 || e1->op == TOKthis)
+           )
+        {
+            bool result = true;
+
+            var->ctorinit = true;
+            //printf("setting ctorinit\n");
+
+            if (var->isField() && sc->fieldinit && !sc->intypeof)
+            {
+                assert(e1);
+                bool mustInit = ((var->storage_class & STCnodefaultctor) != 0 ||
+                                 var->type->needsNested());
+
+                size_t dim = sc->fieldinit_dim;
+                AggregateDeclaration *ad = fd->isMember2();
+                assert(ad);
+                size_t i;
+                for (i = 0; i < dim; i++)   // same as findFieldIndexByName in ctfeexp.c ?
+                {
+                    if (ad->fields[i] == var)
+                        break;
+                }
+                assert(i < dim);
+                unsigned fi = sc->fieldinit[i];
+
+                if (fi & CSXthis_ctor)
+                {
+                    if (var->type->isMutable() && e1->type->isMutable())
+                        result = false;
+                    else
+                    {
+                        const char *modStr = !var->type->isMutable() ? MODtoChars(var->type->mod) : MODtoChars(e1->type->mod);
+                        ::error(loc, "%s field '%s' initialized multiple times", modStr, var->toChars());
+                    }
+                }
+                else if (sc->noctor || (fi & CSXlabel))
+                {
+                    if (!mustInit && var->type->isMutable() && e1->type->isMutable())
+                        result = false;
+                    else
+                    {
+                        const char *modStr = !var->type->isMutable() ? MODtoChars(var->type->mod) : MODtoChars(e1->type->mod);
+                        ::error(loc, "%s field '%s' initialization is not allowed in loops or after labels", modStr, var->toChars());
+                    }
+                }
+                sc->fieldinit[i] |= CSXthis_ctor;
+                if (var->overlapped) // Bugzilla 15258
+                {
+                    for (size_t j = 0; j < ad->fields.dim; j++)
+                    {
+                        VarDeclaration *v = ad->fields[j];
+                        if (v == var || !var->isOverlappedWith(v))
+                            continue;
+                        v->ctorinit = true;
+                        sc->fieldinit[j] = CSXthis_ctor;
+                    }
+                }
+            }
+            else if (fd != sc->func)
+            {
+                if (var->type->isMutable())
+                    result = false;
+                else if (sc->func->fes)
+                {
+                    const char *p = var->isField() ? "field" : var->kind();
+                    ::error(loc, "%s %s '%s' initialization is not allowed in foreach loop",
+                        MODtoChars(var->type->mod), p, var->toChars());
+                }
+                else
+                {
+                    const char *p = var->isField() ? "field" : var->kind();
+                    ::error(loc, "%s %s '%s' initialization is not allowed in nested function '%s'",
+                        MODtoChars(var->type->mod), p, var->toChars(), sc->func->toChars());
+                }
+            }
+            return result;
+        }
+        else
+        {
+            if (s)
+            {
+                s = s->toParent2();
+                continue;
+            }
+        }
+        break;
+    }
+    return false;
+}
+
+int DotVarExp::checkModifiable(Scope *sc, int flag)
+{
+    //printf("DotVarExp::checkModifiable %s %s\n", toChars(), type->toChars());
+    if (checkUnsafeAccess(sc, this, false, !flag))
+        return 2;
+
+    if (e1->op == TOKthis)
+        return var->checkModify(loc, sc, type, e1, flag);
+
+    //printf("\te1 = %s\n", e1->toChars());
+    return e1->checkModifiable(sc, flag);
+}
+
+Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+#if 0
+    printf("DotVarExp::modifiableLvalue(%s)\n", toChars());
+    printf("e1->type = %s\n", e1->type->toChars());
+    printf("var->type = %s\n", var->type->toChars());
+#endif
+
+    return Expression::modifiableLvalue(sc, e);
+}
+
+/************************************************************/
+
+/* Things like:
+ *      foo.bar!(args)
+ */
+
+DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs)
+        : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e)
+{
+    //printf("DotTemplateInstanceExp()\n");
+    this->ti = new TemplateInstance(loc, name);
+    this->ti->tiargs = tiargs;
+}
+
+DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti)
+        : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e)
+{
+    this->ti = ti;
+}
+
+Expression *DotTemplateInstanceExp::syntaxCopy()
+{
+    return new DotTemplateInstanceExp(loc,
+        e1->syntaxCopy(),
+        ti->name,
+        TemplateInstance::arraySyntaxCopy(ti->tiargs));
+}
+
+bool DotTemplateInstanceExp::findTempDecl(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars());
+#endif
+    if (ti->tempdecl)
+        return true;
+
+    Expression *e = new DotIdExp(loc, e1, ti->name);
+    e = semantic(e, sc);
+    if (e->op == TOKdot)
+        e = ((DotExp *)e)->e2;
+
+    Dsymbol *s = NULL;
+    switch (e->op)
+    {
+        case TOKoverloadset:    s = ((OverExp *)e)->vars;       break;
+        case TOKdottd:          s = ((DotTemplateExp *)e)->td;  break;
+        case TOKscope:          s = ((ScopeExp *)e)->sds;       break;
+        case TOKdotvar:         s = ((DotVarExp *)e)->var;      break;
+        case TOKvar:            s = ((VarExp *)e)->var;         break;
+        default:                return false;
+    }
+    return ti->updateTempDecl(sc, s);
+}
+
+/************************************************************/
+
+DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f, bool hasOverloads)
+        : UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e)
+{
+    this->func = f;
+    this->hasOverloads = hasOverloads;
+}
+
+/************************************************************/
+
+DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s)
+        : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e)
+{
+    this->sym = s;
+    this->type = s->getType();
+}
+
+/************************************************************/
+
+CallExp::CallExp(Loc loc, Expression *e, Expressions *exps)
+        : UnaExp(loc, TOKcall, sizeof(CallExp), e)
+{
+    this->arguments = exps;
+    this->f = NULL;
+    this->directcall = false;
+}
+
+CallExp::CallExp(Loc loc, Expression *e)
+        : UnaExp(loc, TOKcall, sizeof(CallExp), e)
+{
+    this->arguments = NULL;
+    this->f = NULL;
+    this->directcall = false;
+}
+
+CallExp::CallExp(Loc loc, Expression *e, Expression *earg1)
+        : UnaExp(loc, TOKcall, sizeof(CallExp), e)
+{
+    Expressions *arguments = new Expressions();
+    if (earg1)
+    {
+        arguments->setDim(1);
+        (*arguments)[0] = earg1;
+    }
+    this->arguments = arguments;
+    this->f = NULL;
+    this->directcall = false;
+}
+
+CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2)
+        : UnaExp(loc, TOKcall, sizeof(CallExp), e)
+{
+    Expressions *arguments = new Expressions();
+    arguments->setDim(2);
+    (*arguments)[0] = earg1;
+    (*arguments)[1] = earg2;
+
+    this->arguments = arguments;
+    this->f = NULL;
+    this->directcall = false;
+}
+
+CallExp *CallExp::create(Loc loc, Expression *e, Expressions *exps)
+{
+    return new CallExp(loc, e, exps);
+}
+
+CallExp *CallExp::create(Loc loc, Expression *e)
+{
+    return new CallExp(loc, e);
+}
+
+CallExp *CallExp::create(Loc loc, Expression *e, Expression *earg1)
+{
+    return new CallExp(loc, e, earg1);
+}
+
+Expression *CallExp::syntaxCopy()
+{
+    return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments));
+}
+
+bool CallExp::isLvalue()
+{
+    Type *tb = e1->type->toBasetype();
+    if (tb->ty == Tdelegate || tb->ty == Tpointer)
+        tb = tb->nextOf();
+    if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref)
+    {
+        if (e1->op == TOKdotvar)
+            if (((DotVarExp *)e1)->var->isCtorDeclaration())
+                return false;
+        return true;               // function returns a reference
+    }
+    return false;
+}
+
+Expression *CallExp::toLvalue(Scope *sc, Expression *e)
+{
+    if (isLvalue())
+        return this;
+    return Expression::toLvalue(sc, e);
+}
+
+Expression *CallExp::addDtorHook(Scope *sc)
+{
+    /* Only need to add dtor hook if it's a type that needs destruction.
+     * Use same logic as VarDeclaration::callScopeDtor()
+     */
+
+    if (e1->type && e1->type->ty == Tfunction)
+    {
+        TypeFunction *tf = (TypeFunction *)e1->type;
+        if (tf->isref)
+            return this;
+    }
+
+    Type *tv = type->baseElemOf();
+    if (tv->ty == Tstruct)
+    {
+        TypeStruct *ts = (TypeStruct *)tv;
+        StructDeclaration *sd = ts->sym;
+        if (sd->dtor)
+        {
+            /* Type needs destruction, so declare a tmp
+             * which the back end will recognize and call dtor on
+             */
+            VarDeclaration *tmp = copyToTemp(0, "__tmpfordtor", this);
+            DeclarationExp *de = new DeclarationExp(loc, tmp);
+            VarExp *ve = new VarExp(loc, tmp);
+            Expression *e = new CommaExp(loc, de, ve);
+            e = semantic(e, sc);
+            return e;
+        }
+    }
+    return this;
+}
+
+FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL)
+{
+    if (e->op == TOKaddress)
+    {
+        Expression *ae1 = ((AddrExp *)e)->e1;
+        if (ae1->op == TOKvar)
+        {
+            VarExp *ve = (VarExp *)ae1;
+            if (hasOverloads)
+                *hasOverloads = ve->hasOverloads;
+            return ve->var->isFuncDeclaration();
+        }
+        if (ae1->op == TOKdotvar)
+        {
+            DotVarExp *dve = (DotVarExp *)ae1;
+            if (hasOverloads)
+                *hasOverloads = dve->hasOverloads;
+            return dve->var->isFuncDeclaration();
+        }
+    }
+    else
+    {
+        if (e->op == TOKsymoff)
+        {
+            SymOffExp *soe = (SymOffExp *)e;
+            if (hasOverloads)
+                *hasOverloads = soe->hasOverloads;
+            return soe->var->isFuncDeclaration();
+        }
+        if (e->op == TOKdelegate)
+        {
+            DelegateExp *dge = (DelegateExp *)e;
+            if (hasOverloads)
+                *hasOverloads = dge->hasOverloads;
+            return dge->func->isFuncDeclaration();
+        }
+    }
+    return NULL;
+}
+
+/************************************************************/
+
+AddrExp::AddrExp(Loc loc, Expression *e)
+        : UnaExp(loc, TOKaddress, sizeof(AddrExp), e)
+{
+}
+
+/************************************************************/
+
+PtrExp::PtrExp(Loc loc, Expression *e)
+        : UnaExp(loc, TOKstar, sizeof(PtrExp), e)
+{
+//    if (e->type)
+//      type = ((TypePointer *)e->type)->next;
+}
+
+PtrExp::PtrExp(Loc loc, Expression *e, Type *t)
+        : UnaExp(loc, TOKstar, sizeof(PtrExp), e)
+{
+    type = t;
+}
+
+bool PtrExp::isLvalue()
+{
+    return true;
+}
+
+Expression *PtrExp::toLvalue(Scope *sc, Expression *e)
+{
+    return this;
+}
+
+int PtrExp::checkModifiable(Scope *sc, int flag)
+{
+    if (e1->op == TOKsymoff)
+    {   SymOffExp *se = (SymOffExp *)e1;
+        return se->var->checkModify(loc, sc, type, NULL, flag);
+    }
+    else if (e1->op == TOKaddress)
+    {
+        AddrExp *ae = (AddrExp *)e1;
+        return ae->e1->checkModifiable(sc, flag);
+    }
+    return 1;
+}
+
+Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars());
+    return Expression::modifiableLvalue(sc, e);
+}
+
+/************************************************************/
+
+NegExp::NegExp(Loc loc, Expression *e)
+        : UnaExp(loc, TOKneg, sizeof(NegExp), e)
+{
+}
+
+/************************************************************/
+
+UAddExp::UAddExp(Loc loc, Expression *e)
+        : UnaExp(loc, TOKuadd, sizeof(UAddExp), e)
+{
+}
+
+/************************************************************/
+
+ComExp::ComExp(Loc loc, Expression *e)
+        : UnaExp(loc, TOKtilde, sizeof(ComExp), e)
+{
+}
+
+/************************************************************/
+
+NotExp::NotExp(Loc loc, Expression *e)
+        : UnaExp(loc, TOKnot, sizeof(NotExp), e)
+{
+}
+
+/************************************************************/
+
+DeleteExp::DeleteExp(Loc loc, Expression *e, bool isRAII)
+        : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e)
+{
+    this->isRAII = isRAII;
+}
+
+Expression *DeleteExp::toBoolean(Scope *sc)
+{
+    error("delete does not give a boolean result");
+    return new ErrorExp();
+}
+
+/************************************************************/
+
+CastExp::CastExp(Loc loc, Expression *e, Type *t)
+        : UnaExp(loc, TOKcast, sizeof(CastExp), e)
+{
+    this->to = t;
+    this->mod = (unsigned char)~0;
+}
+
+/* For cast(const) and cast(immutable)
+ */
+CastExp::CastExp(Loc loc, Expression *e, unsigned char mod)
+        : UnaExp(loc, TOKcast, sizeof(CastExp), e)
+{
+    this->to = NULL;
+    this->mod = mod;
+}
+
+Expression *CastExp::syntaxCopy()
+{
+    return to ? new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy())
+              : new CastExp(loc, e1->syntaxCopy(), mod);
+}
+
+/************************************************************/
+
+VectorExp::VectorExp(Loc loc, Expression *e, Type *t)
+        : UnaExp(loc, TOKvector, sizeof(VectorExp), e)
+{
+    assert(t->ty == Tvector);
+    to = (TypeVector *)t;
+    dim = ~0;
+}
+
+VectorExp *VectorExp::create(Loc loc, Expression *e, Type *t)
+{
+    return new VectorExp(loc, e, t);
+}
+
+Expression *VectorExp::syntaxCopy()
+{
+    return new VectorExp(loc, e1->syntaxCopy(), to->syntaxCopy());
+}
+
+/************************************************************/
+
+SliceExp::SliceExp(Loc loc, Expression *e1, IntervalExp *ie)
+        : UnaExp(loc, TOKslice, sizeof(SliceExp), e1)
+{
+    this->upr = ie ? ie->upr : NULL;
+    this->lwr = ie ? ie->lwr : NULL;
+    lengthVar = NULL;
+    upperIsInBounds = false;
+    lowerIsLessThanUpper = false;
+}
+
+SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr)
+        : UnaExp(loc, TOKslice, sizeof(SliceExp), e1)
+{
+    this->upr = upr;
+    this->lwr = lwr;
+    lengthVar = NULL;
+    upperIsInBounds = false;
+    lowerIsLessThanUpper = false;
+}
+
+Expression *SliceExp::syntaxCopy()
+{
+    SliceExp *se = new SliceExp(loc, e1->syntaxCopy(),
+        lwr ? lwr->syntaxCopy() : NULL,
+        upr ? upr->syntaxCopy() : NULL);
+    se->lengthVar = this->lengthVar;    // bug7871
+    return se;
+}
+
+int SliceExp::checkModifiable(Scope *sc, int flag)
+{
+    //printf("SliceExp::checkModifiable %s\n", toChars());
+    if (e1->type->ty == Tsarray ||
+        (e1->op == TOKindex && e1->type->ty != Tarray) ||
+        e1->op == TOKslice)
+    {
+        return e1->checkModifiable(sc, flag);
+    }
+    return 1;
+}
+
+bool SliceExp::isLvalue()
+{
+    /* slice expression is rvalue in default, but
+     * conversion to reference of static array is only allowed.
+     */
+    return (type && type->toBasetype()->ty == Tsarray);
+}
+
+Expression *SliceExp::toLvalue(Scope *sc, Expression *e)
+{
+    //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type->toChars() : NULL);
+    return (type && type->toBasetype()->ty == Tsarray)
+            ? this : Expression::toLvalue(sc, e);
+}
+
+Expression *SliceExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    error("slice expression %s is not a modifiable lvalue", toChars());
+    return this;
+}
+
+bool SliceExp::isBool(bool result)
+{
+    return e1->isBool(result);
+}
+
+/********************** ArrayLength **************************************/
+
+ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1)
+        : UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1)
+{
+}
+
+Expression *opAssignToOp(Loc loc, TOK op, Expression *e1, Expression *e2)
+{   Expression *e;
+
+    switch (op)
+    {
+        case TOKaddass:   e = new AddExp(loc, e1, e2);  break;
+        case TOKminass:   e = new MinExp(loc, e1, e2);  break;
+        case TOKmulass:   e = new MulExp(loc, e1, e2);  break;
+        case TOKdivass:   e = new DivExp(loc, e1, e2);  break;
+        case TOKmodass:   e = new ModExp(loc, e1, e2);  break;
+        case TOKandass:   e = new AndExp(loc, e1, e2);  break;
+        case TOKorass:    e = new OrExp (loc, e1, e2);  break;
+        case TOKxorass:   e = new XorExp(loc, e1, e2);  break;
+        case TOKshlass:   e = new ShlExp(loc, e1, e2);  break;
+        case TOKshrass:   e = new ShrExp(loc, e1, e2);  break;
+        case TOKushrass:  e = new UshrExp(loc, e1, e2); break;
+        default:        assert(0);
+    }
+    return e;
+}
+
+/*********************
+ * Rewrite:
+ *    array.length op= e2
+ * as:
+ *    array.length = array.length op e2
+ * or:
+ *    auto tmp = &array;
+ *    (*tmp).length = (*tmp).length op e2
+ */
+
+Expression *ArrayLengthExp::rewriteOpAssign(BinExp *exp)
+{
+    Expression *e;
+
+    assert(exp->e1->op == TOKarraylength);
+    ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1;
+    if (ale->e1->op == TOKvar)
+    {
+        e = opAssignToOp(exp->loc, exp->op, ale, exp->e2);
+        e = new AssignExp(exp->loc, ale->syntaxCopy(), e);
+    }
+    else
+    {
+        /*    auto tmp = &array;
+         *    (*tmp).length = (*tmp).length op e2
+         */
+        VarDeclaration *tmp = copyToTemp(0, "__arraylength", new AddrExp(ale->loc, ale->e1));
+
+        Expression *e1 = new ArrayLengthExp(ale->loc, new PtrExp(ale->loc, new VarExp(ale->loc, tmp)));
+        Expression *elvalue = e1->syntaxCopy();
+        e = opAssignToOp(exp->loc, exp->op, e1, exp->e2);
+        e = new AssignExp(exp->loc, elvalue, e);
+        e = new CommaExp(exp->loc, new DeclarationExp(ale->loc, tmp), e);
+    }
+    return e;
+}
+
+/*********************** IntervalExp ********************************/
+
+// Mainly just a placeholder
+
+IntervalExp::IntervalExp(Loc loc, Expression *lwr, Expression *upr)
+        : Expression(loc, TOKinterval, sizeof(IntervalExp))
+{
+    this->lwr = lwr;
+    this->upr = upr;
+}
+
+Expression *IntervalExp::syntaxCopy()
+{
+    return new IntervalExp(loc, lwr->syntaxCopy(), upr->syntaxCopy());
+}
+
+/********************** DelegatePtrExp **************************************/
+
+DelegatePtrExp::DelegatePtrExp(Loc loc, Expression *e1)
+        : UnaExp(loc, TOKdelegateptr, sizeof(DelegatePtrExp), e1)
+{
+}
+
+bool DelegatePtrExp::isLvalue()
+{
+    return e1->isLvalue();
+}
+
+Expression *DelegatePtrExp::toLvalue(Scope *sc, Expression *e)
+{
+    e1 = e1->toLvalue(sc, e);
+    return this;
+}
+
+Expression *DelegatePtrExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    if (sc->func->setUnsafe())
+    {
+        error("cannot modify delegate pointer in @safe code %s", toChars());
+        return new ErrorExp();
+    }
+    return Expression::modifiableLvalue(sc, e);
+}
+
+/********************** DelegateFuncptrExp **************************************/
+
+DelegateFuncptrExp::DelegateFuncptrExp(Loc loc, Expression *e1)
+        : UnaExp(loc, TOKdelegatefuncptr, sizeof(DelegateFuncptrExp), e1)
+{
+}
+
+bool DelegateFuncptrExp::isLvalue()
+{
+    return e1->isLvalue();
+}
+
+Expression *DelegateFuncptrExp::toLvalue(Scope *sc, Expression *e)
+{
+    e1 = e1->toLvalue(sc, e);
+    return this;
+}
+
+Expression *DelegateFuncptrExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    if (sc->func->setUnsafe())
+    {
+        error("cannot modify delegate function pointer in @safe code %s", toChars());
+        return new ErrorExp();
+    }
+    return Expression::modifiableLvalue(sc, e);
+}
+
+/*********************** ArrayExp *************************************/
+
+// e1 [ i1, i2, i3, ... ]
+
+ArrayExp::ArrayExp(Loc loc, Expression *e1, Expression *index)
+        : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1)
+{
+    arguments = new Expressions();
+    if (index)
+        arguments->push(index);
+    lengthVar = NULL;
+    currentDimension = 0;
+}
+
+ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args)
+        : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1)
+{
+    arguments = args;
+    lengthVar = NULL;
+    currentDimension = 0;
+}
+
+Expression *ArrayExp::syntaxCopy()
+{
+    ArrayExp *ae = new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments));
+    ae->lengthVar = this->lengthVar;    // bug7871
+    return ae;
+}
+
+bool ArrayExp::isLvalue()
+{
+    if (type && type->toBasetype()->ty == Tvoid)
+        return false;
+    return true;
+}
+
+Expression *ArrayExp::toLvalue(Scope *sc, Expression *e)
+{
+    if (type && type->toBasetype()->ty == Tvoid)
+        error("voids have no value");
+    return this;
+}
+
+/************************* DotExp ***********************************/
+
+DotExp::DotExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKdot, sizeof(DotExp), e1, e2)
+{
+}
+
+/************************* CommaExp ***********************************/
+
+CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2, bool generated)
+        : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2)
+{
+    isGenerated = generated;
+    allowCommaExp = generated;
+}
+
+bool CommaExp::isLvalue()
+{
+    return e2->isLvalue();
+}
+
+Expression *CommaExp::toLvalue(Scope *sc, Expression *e)
+{
+    e2 = e2->toLvalue(sc, NULL);
+    return this;
+}
+
+int CommaExp::checkModifiable(Scope *sc, int flag)
+{
+    return e2->checkModifiable(sc, flag);
+}
+
+Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    e2 = e2->modifiableLvalue(sc, e);
+    return this;
+}
+
+bool CommaExp::isBool(bool result)
+{
+    return e2->isBool(result);
+}
+
+Expression *CommaExp::toBoolean(Scope *sc)
+{
+    Expression *ex2 = e2->toBoolean(sc);
+    if (ex2->op == TOKerror)
+        return ex2;
+    e2 = ex2;
+    type = e2->type;
+    return this;
+}
+
+Expression *CommaExp::addDtorHook(Scope *sc)
+{
+    e2 = e2->addDtorHook(sc);
+    return this;
+}
+
+/************************** IndexExp **********************************/
+
+// e1 [ e2 ]
+
+IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2)
+{
+    //printf("IndexExp::IndexExp('%s')\n", toChars());
+    lengthVar = NULL;
+    modifiable = false;     // assume it is an rvalue
+    indexIsInBounds = false;
+}
+
+Expression *IndexExp::syntaxCopy()
+{
+    IndexExp *ie = new IndexExp(loc, e1->syntaxCopy(), e2->syntaxCopy());
+    ie->lengthVar = this->lengthVar;    // bug7871
+    return ie;
+}
+
+bool IndexExp::isLvalue()
+{
+    return true;
+}
+
+Expression *IndexExp::toLvalue(Scope *sc, Expression *e)
+{
+    return this;
+}
+
+int IndexExp::checkModifiable(Scope *sc, int flag)
+{
+    if (e1->type->ty == Tsarray ||
+        e1->type->ty == Taarray ||
+        (e1->op == TOKindex && e1->type->ty != Tarray) ||
+        e1->op == TOKslice)
+    {
+        return e1->checkModifiable(sc, flag);
+    }
+    return 1;
+}
+
+Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
+    Expression *ex = markSettingAAElem();
+    if (ex->op == TOKerror)
+        return ex;
+
+    return Expression::modifiableLvalue(sc, e);
+}
+
+Expression *IndexExp::markSettingAAElem()
+{
+    if (e1->type->toBasetype()->ty == Taarray)
+    {
+        Type *t2b = e2->type->toBasetype();
+        if (t2b->ty == Tarray && t2b->nextOf()->isMutable())
+        {
+            error("associative arrays can only be assigned values with immutable keys, not %s", e2->type->toChars());
+            return new ErrorExp();
+        }
+        modifiable = true;
+
+        if (e1->op == TOKindex)
+        {
+            Expression *ex = ((IndexExp *)e1)->markSettingAAElem();
+            if (ex->op == TOKerror)
+                return ex;
+            assert(ex == e1);
+        }
+    }
+    return this;
+}
+
+/************************* PostExp ***********************************/
+
+PostExp::PostExp(TOK op, Loc loc, Expression *e)
+        : BinExp(loc, op, sizeof(PostExp), e,
+          new IntegerExp(loc, 1, Type::tint32))
+{
+}
+
+/************************* PreExp ***********************************/
+
+PreExp::PreExp(TOK op, Loc loc, Expression *e)
+        : UnaExp(loc, op, sizeof(PreExp), e)
+{
+}
+
+/************************************************************/
+
+/* op can be TOKassign, TOKconstruct, or TOKblit */
+
+AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2)
+{
+    memset = 0;
+}
+
+bool AssignExp::isLvalue()
+{
+    // Array-op 'x[] = y[]' should make an rvalue.
+    // Setting array length 'x.length = v' should make an rvalue.
+    if (e1->op == TOKslice ||
+        e1->op == TOKarraylength)
+    {
+        return false;
+    }
+    return true;
+}
+
+Expression *AssignExp::toLvalue(Scope *sc, Expression *ex)
+{
+    if (e1->op == TOKslice ||
+        e1->op == TOKarraylength)
+    {
+        return Expression::toLvalue(sc, ex);
+    }
+
+    /* In front-end level, AssignExp should make an lvalue of e1.
+     * Taking the address of e1 will be handled in low level layer,
+     * so this function does nothing.
+     */
+    return this;
+}
+
+Expression *AssignExp::toBoolean(Scope *sc)
+{
+    // Things like:
+    //  if (a = b) ...
+    // are usually mistakes.
+
+    error("assignment cannot be used as a condition, perhaps == was meant?");
+    return new ErrorExp();
+}
+
+/************************************************************/
+
+ConstructExp::ConstructExp(Loc loc, Expression *e1, Expression *e2)
+    : AssignExp(loc, e1, e2)
+{
+    op = TOKconstruct;
+}
+
+ConstructExp::ConstructExp(Loc loc, VarDeclaration *v, Expression *e2)
+    : AssignExp(loc, new VarExp(loc, v), e2)
+{
+    assert(v->type && e1->type);
+    op = TOKconstruct;
+
+    if (v->storage_class & (STCref | STCout))
+        memset |= referenceInit;
+}
+
+/************************************************************/
+
+BlitExp::BlitExp(Loc loc, Expression *e1, Expression *e2)
+    : AssignExp(loc, e1, e2)
+{
+    op = TOKblit;
+}
+
+BlitExp::BlitExp(Loc loc, VarDeclaration *v, Expression *e2)
+    : AssignExp(loc, new VarExp(loc, v), e2)
+{
+    assert(v->type && e1->type);
+    op = TOKblit;
+
+    if (v->storage_class & (STCref | STCout))
+        memset |= referenceInit;
+}
+
+/************************************************************/
+
+AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2)
+{
+}
+
+/***************** PowAssignExp *******************************************/
+
+PowAssignExp::PowAssignExp(Loc loc, Expression *e1, Expression *e2)
+        : BinAssignExp(loc, TOKpowass, sizeof(PowAssignExp), e1, e2)
+{
+}
+
+/************************* AddExp *****************************/
+
+AddExp::AddExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+MinExp::MinExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKmin, sizeof(MinExp), e1, e2)
+{
+}
+
+/************************* CatExp *****************************/
+
+CatExp::CatExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKcat, sizeof(CatExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+MulExp::MulExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKmul, sizeof(MulExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+DivExp::DivExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+ModExp::ModExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+PowExp::PowExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKpow, sizeof(PowExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+ShlExp::ShlExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKshl, sizeof(ShlExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+AndExp::AndExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKand, sizeof(AndExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+OrExp::OrExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKor, sizeof(OrExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+XorExp::XorExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKxor, sizeof(XorExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+OrOrExp::OrOrExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKoror, sizeof(OrOrExp), e1, e2)
+{
+}
+
+Expression *OrOrExp::toBoolean(Scope *sc)
+{
+    Expression *ex2 = e2->toBoolean(sc);
+    if (ex2->op == TOKerror)
+        return ex2;
+    e2 = ex2;
+    return this;
+}
+
+/************************************************************/
+
+AndAndExp::AndAndExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKandand, sizeof(AndAndExp), e1, e2)
+{
+}
+
+Expression *AndAndExp::toBoolean(Scope *sc)
+{
+    Expression *ex2 = e2->toBoolean(sc);
+    if (ex2->op == TOKerror)
+        return ex2;
+    e2 = ex2;
+    return this;
+}
+
+/************************************************************/
+
+InExp::InExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKin, sizeof(InExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+/* This deletes the key e1 from the associative array e2
+ */
+
+RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2)
+{
+    type = Type::tbool;
+}
+
+/************************************************************/
+
+CmpExp::CmpExp(TOK op, Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, op, sizeof(CmpExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+EqualExp::EqualExp(TOK op, Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, op, sizeof(EqualExp), e1, e2)
+{
+    assert(op == TOKequal || op == TOKnotequal);
+}
+
+/************************************************************/
+
+IdentityExp::IdentityExp(TOK op, Loc loc, Expression *e1, Expression *e2)
+        : BinExp(loc, op, sizeof(IdentityExp), e1, e2)
+{
+}
+
+/****************************************************************/
+
+CondExp::CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2)
+        : BinExp(loc, TOKquestion, sizeof(CondExp), e1, e2)
+{
+    this->econd = econd;
+}
+
+Expression *CondExp::syntaxCopy()
+{
+    return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy());
+}
+
+void CondExp::hookDtors(Scope *sc)
+{
+    class DtorVisitor : public StoppableVisitor
+    {
+    public:
+        Scope *sc;
+        CondExp *ce;
+        VarDeclaration *vcond;
+        bool isThen;
+
+        DtorVisitor(Scope *sc, CondExp *ce)
+        {
+            this->sc = sc;
+            this->ce = ce;
+            this->vcond = NULL;
+        }
+
+        void visit(Expression *e)
+        {
+            //printf("(e = %s)\n", e->toChars());
+        }
+
+        void visit(DeclarationExp *e)
+        {
+            VarDeclaration *v = e->declaration->isVarDeclaration();
+            if (v && !v->isDataseg())
+            {
+                if (v->_init)
+                {
+                    ExpInitializer *ei = v->_init->isExpInitializer();
+                    if (ei)
+                        ei->exp->accept(this);
+                }
+
+                if (v->needsScopeDtor())
+                {
+                    if (!vcond)
+                    {
+                        vcond = copyToTemp(STCvolatile, "__cond", ce->econd);
+                        vcond->semantic(sc);
+
+                        Expression *de = new DeclarationExp(ce->econd->loc, vcond);
+                        de = semantic(de, sc);
+
+                        Expression *ve = new VarExp(ce->econd->loc, vcond);
+                        ce->econd = Expression::combine(de, ve);
+                    }
+
+                    //printf("\t++v = %s, v->edtor = %s\n", v->toChars(), v->edtor->toChars());
+                    Expression *ve = new VarExp(vcond->loc, vcond);
+                    if (isThen)
+                        v->edtor = new AndAndExp(v->edtor->loc, ve, v->edtor);
+                    else
+                        v->edtor = new OrOrExp(v->edtor->loc, ve, v->edtor);
+                    v->edtor = semantic(v->edtor, sc);
+                    //printf("\t--v = %s, v->edtor = %s\n", v->toChars(), v->edtor->toChars());
+                }
+            }
+        }
+    };
+
+    DtorVisitor v(sc, this);
+    //printf("+%s\n", toChars());
+    v.isThen = true;    walkPostorder(e1, &v);
+    v.isThen = false;   walkPostorder(e2, &v);
+    //printf("-%s\n", toChars());
+}
+
+bool CondExp::isLvalue()
+{
+    return e1->isLvalue() && e2->isLvalue();
+}
+
+
+Expression *CondExp::toLvalue(Scope *sc, Expression *ex)
+{
+    // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
+    CondExp *e = (CondExp *)copy();
+    e->e1 = e1->toLvalue(sc, NULL)->addressOf();
+    e->e2 = e2->toLvalue(sc, NULL)->addressOf();
+    e->type = type->pointerTo();
+    return new PtrExp(loc, e, type);
+}
+
+int CondExp::checkModifiable(Scope *sc, int flag)
+{
+    return e1->checkModifiable(sc, flag) && e2->checkModifiable(sc, flag);
+}
+
+Expression *CondExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    //error("conditional expression %s is not a modifiable lvalue", toChars());
+    e1 = e1->modifiableLvalue(sc, e1);
+    e2 = e2->modifiableLvalue(sc, e2);
+    return toLvalue(sc, this);
+}
+
+Expression *CondExp::toBoolean(Scope *sc)
+{
+    Expression *ex1 = e1->toBoolean(sc);
+    Expression *ex2 = e2->toBoolean(sc);
+    if (ex1->op == TOKerror)
+        return ex1;
+    if (ex2->op == TOKerror)
+        return ex2;
+    e1 = ex1;
+    e2 = ex2;
+    return this;
+}
+
+/****************************************************************/
+
+DefaultInitExp::DefaultInitExp(Loc loc, TOK subop, int size)
+    : Expression(loc, TOKdefault, size)
+{
+    this->subop = subop;
+}
+
+/****************************************************************/
+
+FileInitExp::FileInitExp(Loc loc, TOK tok)
+    : DefaultInitExp(loc, tok, sizeof(FileInitExp))
+{
+}
+
+Expression *FileInitExp::resolveLoc(Loc loc, Scope *sc)
+{
+    //printf("FileInitExp::resolve() %s\n", toChars());
+    const char *s = loc.filename ? loc.filename : sc->_module->ident->toChars();
+    Expression *e = new StringExp(loc, (char *)s);
+    e = semantic(e, sc);
+    e = e->castTo(sc, type);
+    return e;
+}
+
+/****************************************************************/
+
+LineInitExp::LineInitExp(Loc loc)
+    : DefaultInitExp(loc, TOKline, sizeof(LineInitExp))
+{
+}
+
+Expression *LineInitExp::resolveLoc(Loc loc, Scope *sc)
+{
+    Expression *e = new IntegerExp(loc, loc.linnum, Type::tint32);
+    e = e->castTo(sc, type);
+    return e;
+}
+
+/****************************************************************/
+
+ModuleInitExp::ModuleInitExp(Loc loc)
+    : DefaultInitExp(loc, TOKmodulestring, sizeof(ModuleInitExp))
+{
+}
+
+Expression *ModuleInitExp::resolveLoc(Loc loc, Scope *sc)
+{
+    const char *s;
+    if (sc->callsc)
+        s = sc->callsc->_module->toPrettyChars();
+    else
+        s = sc->_module->toPrettyChars();
+    Expression *e = new StringExp(loc, (char *)s);
+    e = semantic(e, sc);
+    e = e->castTo(sc, type);
+    return e;
+}
+
+/****************************************************************/
+
+FuncInitExp::FuncInitExp(Loc loc)
+    : DefaultInitExp(loc, TOKfuncstring, sizeof(FuncInitExp))
+{
+}
+
+Expression *FuncInitExp::resolveLoc(Loc loc, Scope *sc)
+{
+    const char *s;
+    if (sc->callsc && sc->callsc->func)
+        s = sc->callsc->func->Dsymbol::toPrettyChars();
+    else if (sc->func)
+        s = sc->func->Dsymbol::toPrettyChars();
+    else
+        s = "";
+    Expression *e = new StringExp(loc, (char *)s);
+    e = semantic(e, sc);
+    e = e->castTo(sc, type);
+    return e;
+}
+
+/****************************************************************/
+
+PrettyFuncInitExp::PrettyFuncInitExp(Loc loc)
+    : DefaultInitExp(loc, TOKprettyfunc, sizeof(PrettyFuncInitExp))
+{
+}
+
+Expression *PrettyFuncInitExp::resolveLoc(Loc loc, Scope *sc)
+{
+    FuncDeclaration *fd;
+    if (sc->callsc && sc->callsc->func)
+        fd = sc->callsc->func;
+    else
+        fd = sc->func;
+
+    const char *s;
+    if (fd)
+    {
+        const char *funcStr = fd->Dsymbol::toPrettyChars();
+        OutBuffer buf;
+        functionToBufferWithIdent((TypeFunction *)fd->type, &buf, funcStr);
+        s = buf.extractString();
+    }
+    else
+    {
+        s = "";
+    }
+
+    Expression *e = new StringExp(loc, (char *)s);
+    e = semantic(e, sc);
+    e = e->castTo(sc, type);
+    return e;
+}
+
+/****************************************************************/
+
+Expression *extractOpDollarSideEffect(Scope *sc, UnaExp *ue)
+{
+    Expression *e0;
+    Expression *e1 = Expression::extractLast(ue->e1, &e0);
+    // Bugzilla 12585: Extract the side effect part if ue->e1 is comma.
+
+    if (!isTrivialExp(e1))
+    {
+        /* Even if opDollar is needed, 'e1' should be evaluate only once. So
+         * Rewrite:
+         *      e1.opIndex( ... use of $ ... )
+         *      e1.opSlice( ... use of $ ... )
+         * as:
+         *      (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
+         *      (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
+         */
+        e1 = extractSideEffect(sc, "__dop", &e0, e1, false);
+        assert(e1->op == TOKvar);
+        VarExp *ve = (VarExp *)e1;
+        ve->var->storage_class |= STCexptemp;     // lifetime limited to expression
+    }
+    ue->e1 = e1;
+    return e0;
+}
+
+/**************************************
+ * Runs semantic on ae->arguments. Declares temporary variables
+ * if '$' was used.
+ */
+Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0)
+{
+    assert(!ae->lengthVar);
+
+    *pe0 = NULL;
+
+    AggregateDeclaration *ad = isAggregate(ae->e1->type);
+    Dsymbol *slice = search_function(ad, Id::slice);
+    //printf("slice = %s %s\n", slice->kind(), slice->toChars());
+
+    for (size_t i = 0; i < ae->arguments->dim; i++)
+    {
+        if (i == 0)
+            *pe0 = extractOpDollarSideEffect(sc, ae);
+
+        Expression *e = (*ae->arguments)[i];
+        if (e->op == TOKinterval && !(slice && slice->isTemplateDeclaration()))
+        {
+        Lfallback:
+            if (ae->arguments->dim == 1)
+                return NULL;
+            ae->error("multi-dimensional slicing requires template opSlice");
+            return new ErrorExp();
+        }
+        //printf("[%d] e = %s\n", i, e->toChars());
+
+        // Create scope for '$' variable for this dimension
+        ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
+        sym->loc = ae->loc;
+        sym->parent = sc->scopesym;
+        sc = sc->push(sym);
+        ae->lengthVar = NULL;       // Create it only if required
+        ae->currentDimension = i;   // Dimension for $, if required
+
+        e = semantic(e, sc);
+        e = resolveProperties(sc, e);
+
+        if (ae->lengthVar && sc->func)
+        {
+            // If $ was used, declare it now
+            Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
+            de = semantic(de, sc);
+            *pe0 = Expression::combine(*pe0, de);
+        }
+        sc = sc->pop();
+
+        if (e->op == TOKinterval)
+        {
+            IntervalExp *ie = (IntervalExp *)e;
+
+            Objects *tiargs = new Objects();
+            Expression *edim = new IntegerExp(ae->loc, i, Type::tsize_t);
+            edim = semantic(edim, sc);
+            tiargs->push(edim);
+
+            Expressions *fargs = new Expressions();
+            fargs->push(ie->lwr);
+            fargs->push(ie->upr);
+
+            unsigned xerrors = global.startGagging();
+            sc = sc->push();
+            FuncDeclaration *fslice = resolveFuncCall(ae->loc, sc, slice, tiargs, ae->e1->type, fargs, 1);
+            sc = sc->pop();
+            global.endGagging(xerrors);
+            if (!fslice)
+                goto Lfallback;
+
+            e = new DotTemplateInstanceExp(ae->loc, ae->e1, slice->ident, tiargs);
+            e = new CallExp(ae->loc, e, fargs);
+            e = semantic(e, sc);
+        }
+
+        if (!e->type)
+        {
+            ae->error("%s has no value", e->toChars());
+            e = new ErrorExp();
+        }
+        if (e->op == TOKerror)
+            return e;
+
+        (*ae->arguments)[i] = e;
+    }
+
+    return ae;
+}
+
+/**************************************
+ * Runs semantic on se->lwr and se->upr. Declares a temporary variable
+ * if '$' was used.
+ */
+Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0)
+{
+    //assert(!ae->lengthVar);
+    if (!ie)
+        return ae;
+
+    VarDeclaration *lengthVar = ae->lengthVar;
+
+    // create scope for '$'
+    ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
+    sym->loc = ae->loc;
+    sym->parent = sc->scopesym;
+    sc = sc->push(sym);
+
+    for (size_t i = 0; i < 2; ++i)
+    {
+        Expression *e = i == 0 ? ie->lwr : ie->upr;
+        e = semantic(e, sc);
+        e = resolveProperties(sc, e);
+        if (!e->type)
+        {
+            ae->error("%s has no value", e->toChars());
+            return new ErrorExp();
+        }
+        (i == 0 ? ie->lwr : ie->upr) = e;
+    }
+
+    if (lengthVar != ae->lengthVar && sc->func)
+    {
+        // If $ was used, declare it now
+        Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
+        de = semantic(de, sc);
+        *pe0 = Expression::combine(*pe0, de);
+    }
+    sc = sc->pop();
+
+    return ae;
+}
+
+Expression *BinExp::reorderSettingAAElem(Scope *sc)
+{
+    BinExp *be = this;
+
+    if (be->e1->op != TOKindex)
+        return be;
+    IndexExp *ie = (IndexExp *)be->e1;
+    if (ie->e1->type->toBasetype()->ty != Taarray)
+        return be;
+
+    /* Fix evaluation order of setting AA element. (Bugzilla 3825)
+     * Rewrite:
+     *     aa[k1][k2][k3] op= val;
+     * as:
+     *     auto ref __aatmp = aa;
+     *     auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
+     *     auto ref __aaval = val;
+     *     __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval;  // assignment
+     */
+
+    Expression *e0 = NULL;
+    while (1)
+    {
+        Expression *de = NULL;
+        ie->e2 = extractSideEffect(sc, "__aakey", &de, ie->e2);
+        e0 = Expression::combine(de, e0);
+
+        Expression *ie1 = ie->e1;
+        if (ie1->op != TOKindex ||
+            ((IndexExp *)ie1)->e1->type->toBasetype()->ty != Taarray)
+        {
+            break;
+        }
+        ie = (IndexExp *)ie1;
+    }
+    assert(ie->e1->type->toBasetype()->ty == Taarray);
+
+    Expression *de = NULL;
+    ie->e1 = extractSideEffect(sc, "__aatmp", &de, ie->e1);
+    e0 = Expression::combine(de, e0);
+
+    be->e2 = extractSideEffect(sc, "__aaval", &e0, be->e2, true);
+
+    //printf("-e0 = %s, be = %s\n", e0->toChars(), be->toChars());
+    return Expression::combine(e0, be);
+}
diff --git a/gcc/d/dfrontend/expression.h b/gcc/d/dfrontend/expression.h
new file mode 100644
index 00000000000..a7843e54ea8
--- /dev/null
+++ b/gcc/d/dfrontend/expression.h
@@ -0,0 +1,1561 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/expression.h
+ */
+
+#ifndef DMD_EXPRESSION_H
+#define DMD_EXPRESSION_H
+
+#include "mars.h"
+#include "identifier.h"
+#include "arraytypes.h"
+#include "intrange.h"
+#include "visitor.h"
+#include "tokens.h"
+
+#include "rmem.h"
+
+class Type;
+class TypeVector;
+struct Scope;
+class TupleDeclaration;
+class VarDeclaration;
+class FuncDeclaration;
+class FuncLiteralDeclaration;
+class Declaration;
+class CtorDeclaration;
+class NewDeclaration;
+class Dsymbol;
+class Import;
+class Module;
+class ScopeDsymbol;
+class Expression;
+class Declaration;
+class AggregateDeclaration;
+class StructDeclaration;
+class TemplateInstance;
+class TemplateDeclaration;
+class ClassDeclaration;
+class BinExp;
+class OverloadSet;
+class Initializer;
+class StringExp;
+class ArrayExp;
+class SliceExp;
+struct UnionExp;
+#ifdef IN_GCC
+typedef union tree_node Symbol;
+#else
+struct Symbol;          // back end symbol
+#endif
+
+Expression *resolveProperties(Scope *sc, Expression *e);
+Expression *resolvePropertiesOnly(Scope *sc, Expression *e1);
+bool checkAccess(Loc loc, Scope *sc, Expression *e, Declaration *d);
+bool checkAccess(Loc loc, Scope *sc, Package *p);
+Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Dsymbol *d);
+Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid);
+void expandTuples(Expressions *exps);
+TupleDeclaration *isAliasThisTuple(Expression *e);
+int expandAliasThisTuples(Expressions *exps, size_t starti = 0);
+FuncDeclaration *hasThis(Scope *sc);
+Expression *fromConstInitializer(int result, Expression *e);
+bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors = false);
+TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s);
+Expression *valueNoDtor(Expression *e);
+int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1);
+Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag = false);
+Expression *doCopyOrMove(Scope *sc, Expression *e);
+Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0);
+Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0);
+Expression *integralPromotions(Expression *e, Scope *sc);
+bool discardValue(Expression *e);
+bool isTrivialExp(Expression *e);
+
+int isConst(Expression *e);
+Expression *toDelegate(Expression *e, Type* t, Scope *sc);
+AggregateDeclaration *isAggregate(Type *t);
+IntRange getIntRange(Expression *e);
+bool checkNonAssignmentArrayOp(Expression *e, bool suggestion = false);
+bool isUnaArrayOp(TOK op);
+bool isBinArrayOp(TOK op);
+bool isBinAssignArrayOp(TOK op);
+bool isArrayOpOperand(Expression *e);
+Expression *arrayOp(BinExp *e, Scope *sc);
+Expression *arrayOp(BinAssignExp *e, Scope *sc);
+bool hasSideEffect(Expression *e);
+bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow);
+Expression *Expression_optimize(Expression *e, int result, bool keepLvalue);
+MATCH implicitConvTo(Expression *e, Type *t);
+Expression *implicitCastTo(Expression *e, Scope *sc, Type *t);
+Expression *castTo(Expression *e, Scope *sc, Type *t);
+Expression *ctfeInterpret(Expression *);
+Expression *inlineCopy(Expression *e, Scope *sc);
+Expression *op_overload(Expression *e, Scope *sc);
+Type *toStaticArrayType(SliceExp *e);
+Expression *scaleFactor(BinExp *be, Scope *sc);
+Expression *typeCombine(BinExp *be, Scope *sc);
+Expression *inferType(Expression *e, Type *t, int flag = 0);
+Expression *semanticTraits(TraitsExp *e, Scope *sc);
+Type *getIndirection(Type *t);
+
+Expression *checkGC(Scope *sc, Expression *e);
+
+/* Run CTFE on the expression, but allow the expression to be a TypeExp
+ * or a tuple containing a TypeExp. (This is required by pragma(msg)).
+ */
+Expression *ctfeInterpretForPragmaMsg(Expression *e);
+
+enum OwnedBy
+{
+    OWNEDcode,      // normal code expression in AST
+    OWNEDctfe,      // value expression for CTFE
+    OWNEDcache,     // constant value cached for CTFE
+};
+
+#define WANTvalue   0   // default
+#define WANTexpand  1   // expand const/immutable variables if possible
+
+class Expression : public RootObject
+{
+public:
+    Loc loc;                    // file location
+    Type *type;                 // !=NULL means that semantic() has been run
+    TOK op;                     // to minimize use of dynamic_cast
+    unsigned char size;         // # of bytes in Expression so we can copy() it
+    unsigned char parens;       // if this is a parenthesized expression
+
+    Expression(Loc loc, TOK op, int size);
+    static void _init();
+    Expression *copy();
+    virtual Expression *syntaxCopy();
+
+    // kludge for template.isExpression()
+    int dyncast() const { return DYNCAST_EXPRESSION; }
+
+    void print();
+    const char *toChars();
+    void error(const char *format, ...) const;
+    void warning(const char *format, ...) const;
+    void deprecation(const char *format, ...) const;
+
+    // creates a single expression which is effectively (e1, e2)
+    // this new expression does not necessarily need to have valid D source code representation,
+    // for example, it may include declaration expressions
+    static Expression *combine(Expression *e1, Expression *e2);
+    static Expression *extractLast(Expression *e, Expression **pe0);
+    static Expressions *arraySyntaxCopy(Expressions *exps);
+
+    virtual dinteger_t toInteger();
+    virtual uinteger_t toUInteger();
+    virtual real_t toReal();
+    virtual real_t toImaginary();
+    virtual complex_t toComplex();
+    virtual StringExp *toStringExp();
+    virtual bool isLvalue();
+    virtual Expression *toLvalue(Scope *sc, Expression *e);
+    virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
+    Expression *implicitCastTo(Scope *sc, Type *t)
+    {
+        return ::implicitCastTo(this, sc, t);
+    }
+    MATCH implicitConvTo(Type *t)
+    {
+        return ::implicitConvTo(this, t);
+    }
+    Expression *castTo(Scope *sc, Type *t)
+    {
+        return ::castTo(this, sc, t);
+    }
+    virtual Expression *resolveLoc(Loc loc, Scope *sc);
+    virtual bool checkType();
+    virtual bool checkValue();
+    bool checkScalar();
+    bool checkNoBool();
+    bool checkIntegral();
+    bool checkArithmetic();
+    void checkDeprecated(Scope *sc, Dsymbol *s);
+    bool checkPurity(Scope *sc, FuncDeclaration *f);
+    bool checkPurity(Scope *sc, VarDeclaration *v);
+    bool checkSafety(Scope *sc, FuncDeclaration *f);
+    bool checkNogc(Scope *sc, FuncDeclaration *f);
+    bool checkPostblit(Scope *sc, Type *t);
+    bool checkRightThis(Scope *sc);
+    bool checkReadModifyWrite(TOK rmwOp, Expression *ex = NULL);
+    virtual int checkModifiable(Scope *sc, int flag = 0);
+    virtual Expression *toBoolean(Scope *sc);
+    virtual Expression *addDtorHook(Scope *sc);
+    Expression *addressOf();
+    Expression *deref();
+
+    Expression *optimize(int result, bool keepLvalue = false)
+    {
+        return Expression_optimize(this, result, keepLvalue);
+    }
+
+    // Entry point for CTFE.
+    // A compile-time result is required. Give an error if not possible
+    Expression *ctfeInterpret()
+    {
+        return ::ctfeInterpret(this);
+    }
+
+    int isConst() { return ::isConst(this); }
+    virtual bool isBool(bool result);
+    Expression *op_overload(Scope *sc)
+    {
+        return ::op_overload(this, sc);
+    }
+
+    virtual bool hasCode()
+    {
+        return true;
+    }
+
+    virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+class IntegerExp : public Expression
+{
+public:
+    dinteger_t value;
+
+    IntegerExp(Loc loc, dinteger_t value, Type *type);
+    IntegerExp(dinteger_t value);
+    static IntegerExp *create(Loc loc, dinteger_t value, Type *type);
+    bool equals(RootObject *o);
+    dinteger_t toInteger();
+    real_t toReal();
+    real_t toImaginary();
+    complex_t toComplex();
+    bool isBool(bool result);
+    Expression *toLvalue(Scope *sc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+    dinteger_t getInteger() { return value; }
+    void setInteger(dinteger_t value);
+    void normalize();
+};
+
+class ErrorExp : public Expression
+{
+public:
+    ErrorExp();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+
+    static ErrorExp *errorexp; // handy shared value
+};
+
+class RealExp : public Expression
+{
+public:
+    real_t value;
+
+    RealExp(Loc loc, real_t value, Type *type);
+    static RealExp *create(Loc loc, real_t value, Type *type);
+    bool equals(RootObject *o);
+    dinteger_t toInteger();
+    uinteger_t toUInteger();
+    real_t toReal();
+    real_t toImaginary();
+    complex_t toComplex();
+    bool isBool(bool result);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ComplexExp : public Expression
+{
+public:
+    complex_t value;
+
+    ComplexExp(Loc loc, complex_t value, Type *type);
+    static ComplexExp *create(Loc loc, complex_t value, Type *type);
+    bool equals(RootObject *o);
+    dinteger_t toInteger();
+    uinteger_t toUInteger();
+    real_t toReal();
+    real_t toImaginary();
+    complex_t toComplex();
+    bool isBool(bool result);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class IdentifierExp : public Expression
+{
+public:
+    Identifier *ident;
+
+    IdentifierExp(Loc loc, Identifier *ident);
+    static IdentifierExp *create(Loc loc, Identifier *ident);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DollarExp : public IdentifierExp
+{
+public:
+    DollarExp(Loc loc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DsymbolExp : public Expression
+{
+public:
+    Dsymbol *s;
+    bool hasOverloads;
+
+    DsymbolExp(Loc loc, Dsymbol *s, bool hasOverloads = true);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ThisExp : public Expression
+{
+public:
+    VarDeclaration *var;
+
+    ThisExp(Loc loc);
+    bool isBool(bool result);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class SuperExp : public ThisExp
+{
+public:
+    SuperExp(Loc loc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class NullExp : public Expression
+{
+public:
+    unsigned char committed;    // !=0 if type is committed
+
+    NullExp(Loc loc, Type *t = NULL);
+    bool equals(RootObject *o);
+    bool isBool(bool result);
+    StringExp *toStringExp();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class StringExp : public Expression
+{
+public:
+    void *string;       // char, wchar, or dchar data
+    size_t len;         // number of chars, wchars, or dchars
+    unsigned char sz;   // 1: char, 2: wchar, 4: dchar
+    unsigned char committed;    // !=0 if type is committed
+    utf8_t postfix;      // 'c', 'w', 'd'
+    OwnedBy ownedByCtfe;
+
+    StringExp(Loc loc, char *s);
+    StringExp(Loc loc, void *s, size_t len);
+    StringExp(Loc loc, void *s, size_t len, utf8_t postfix);
+    static StringExp *create(Loc loc, char *s);
+    static StringExp *create(Loc loc, void *s, size_t len);
+    bool equals(RootObject *o);
+    StringExp *toStringExp();
+    StringExp *toUTF8(Scope *sc);
+    int compare(RootObject *obj);
+    bool isBool(bool result);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    unsigned charAt(uinteger_t i) const;
+    void accept(Visitor *v) { v->visit(this); }
+    size_t numberOfCodeUnits(int tynto = 0) const;
+    void writeTo(void* dest, bool zero, int tyto = 0) const;
+    char *toPtr();
+};
+
+// Tuple
+
+class TupleExp : public Expression
+{
+public:
+    Expression *e0;     // side-effect part
+    /* Tuple-field access may need to take out its side effect part.
+     * For example:
+     *      foo().tupleof
+     * is rewritten as:
+     *      (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
+     * The declaration of temporary variable __tup will be stored in TupleExp::e0.
+     */
+    Expressions *exps;
+
+    TupleExp(Loc loc, Expression *e0, Expressions *exps);
+    TupleExp(Loc loc, Expressions *exps);
+    TupleExp(Loc loc, TupleDeclaration *tup);
+    Expression *syntaxCopy();
+    bool equals(RootObject *o);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ArrayLiteralExp : public Expression
+{
+public:
+    Expression *basis;
+    Expressions *elements;
+    OwnedBy ownedByCtfe;
+
+    ArrayLiteralExp(Loc loc, Expressions *elements);
+    ArrayLiteralExp(Loc loc, Expression *e);
+    ArrayLiteralExp(Loc loc, Expression *basis, Expressions *elements);
+    static ArrayLiteralExp *create(Loc loc, Expressions *elements);
+    Expression *syntaxCopy();
+    bool equals(RootObject *o);
+    Expression *getElement(d_size_t i);
+    static Expressions* copyElements(Expression *e1, Expression *e2 = NULL);
+    bool isBool(bool result);
+    StringExp *toStringExp();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class AssocArrayLiteralExp : public Expression
+{
+public:
+    Expressions *keys;
+    Expressions *values;
+    OwnedBy ownedByCtfe;
+
+    AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values);
+    bool equals(RootObject *o);
+    Expression *syntaxCopy();
+    bool isBool(bool result);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// scrubReturnValue is running
+#define stageScrub          0x1
+// hasNonConstPointers is running
+#define stageSearchPointers 0x2
+// optimize is running
+#define stageOptimize       0x4
+// apply is running
+#define stageApply          0x8
+//inlineScan is running
+#define stageInlineScan     0x10
+// toCBuffer is running
+#define stageToCBuffer      0x20
+
+class StructLiteralExp : public Expression
+{
+public:
+    StructDeclaration *sd;      // which aggregate this is for
+    Expressions *elements;      // parallels sd->fields[] with NULL entries for fields to skip
+    Type *stype;                // final type of result (can be different from sd's type)
+
+    bool useStaticInit;         // if this is true, use the StructDeclaration's init symbol
+    Symbol *sym;                // back end symbol to initialize with literal
+
+    OwnedBy ownedByCtfe;
+
+    // pointer to the origin instance of the expression.
+    // once a new expression is created, origin is set to 'this'.
+    // anytime when an expression copy is created, 'origin' pointer is set to
+    // 'origin' pointer value of the original expression.
+    StructLiteralExp *origin;
+
+    // those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
+    StructLiteralExp *inlinecopy;
+
+    // anytime when recursive function is calling, 'stageflags' marks with bit flag of
+    // current stage and unmarks before return from this function.
+    // 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
+    // (with infinite recursion) of this expression.
+    int stageflags;
+
+    StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype = NULL);
+    static StructLiteralExp *create(Loc loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
+    bool equals(RootObject *o);
+    Expression *syntaxCopy();
+    Expression *getField(Type *type, unsigned offset);
+    int getFieldIndex(Type *type, unsigned offset);
+    Expression *addDtorHook(Scope *sc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DotIdExp;
+DotIdExp *typeDotIdExp(Loc loc, Type *type, Identifier *ident);
+
+class TypeExp : public Expression
+{
+public:
+    TypeExp(Loc loc, Type *type);
+    Expression *syntaxCopy();
+    bool checkType();
+    bool checkValue();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ScopeExp : public Expression
+{
+public:
+    ScopeDsymbol *sds;
+
+    ScopeExp(Loc loc, ScopeDsymbol *sds);
+    Expression *syntaxCopy();
+    bool checkType();
+    bool checkValue();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TemplateExp : public Expression
+{
+public:
+    TemplateDeclaration *td;
+    FuncDeclaration *fd;
+
+    TemplateExp(Loc loc, TemplateDeclaration *td, FuncDeclaration *fd = NULL);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    bool checkType();
+    bool checkValue();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class NewExp : public Expression
+{
+public:
+    /* thisexp.new(newargs) newtype(arguments)
+     */
+    Expression *thisexp;        // if !NULL, 'this' for class being allocated
+    Expressions *newargs;       // Array of Expression's to call new operator
+    Type *newtype;
+    Expressions *arguments;     // Array of Expression's
+
+    Expression *argprefix;      // expression to be evaluated just before arguments[]
+
+    CtorDeclaration *member;    // constructor function
+    NewDeclaration *allocator;  // allocator function
+    int onstack;                // allocate on stack
+
+    NewExp(Loc loc, Expression *thisexp, Expressions *newargs,
+        Type *newtype, Expressions *arguments);
+    static NewExp *create(Loc loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments);
+    Expression *syntaxCopy();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class NewAnonClassExp : public Expression
+{
+public:
+    /* thisexp.new(newargs) class baseclasses { } (arguments)
+     */
+    Expression *thisexp;        // if !NULL, 'this' for class being allocated
+    Expressions *newargs;       // Array of Expression's to call new operator
+    ClassDeclaration *cd;       // class being instantiated
+    Expressions *arguments;     // Array of Expression's to call class constructor
+
+    NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs,
+        ClassDeclaration *cd, Expressions *arguments);
+    Expression *syntaxCopy();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class SymbolExp : public Expression
+{
+public:
+    Declaration *var;
+    bool hasOverloads;
+    SymbolExp(Loc loc, TOK op, int size, Declaration *var, bool hasOverloads);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// Offset from symbol
+
+class SymOffExp : public SymbolExp
+{
+public:
+    dinteger_t offset;
+
+    SymOffExp(Loc loc, Declaration *var, dinteger_t offset, bool hasOverloads = true);
+    bool isBool(bool result);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// Variable
+
+class VarExp : public SymbolExp
+{
+public:
+    VarExp(Loc loc, Declaration *var, bool hasOverloads = true);
+    static VarExp *create(Loc loc, Declaration *var, bool hasOverloads = true);
+    bool equals(RootObject *o);
+    int checkModifiable(Scope *sc, int flag);
+    bool checkReadModifyWrite();
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// Overload Set
+
+class OverExp : public Expression
+{
+public:
+    OverloadSet *vars;
+
+    OverExp(Loc loc, OverloadSet *s);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// Function/Delegate literal
+
+class FuncExp : public Expression
+{
+public:
+    FuncLiteralDeclaration *fd;
+    TemplateDeclaration *td;
+    TOK tok;
+
+    FuncExp(Loc loc, Dsymbol *s);
+    bool equals(RootObject *o);
+    void genIdent(Scope *sc);
+    Expression *syntaxCopy();
+    MATCH matchType(Type *to, Scope *sc, FuncExp **pfe, int flag = 0);
+    const char *toChars();
+    bool checkType();
+    bool checkValue();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// Declaration of a symbol
+
+// D grammar allows declarations only as statements. However in AST representation
+// it can be part of any expression. This is used, for example, during internal
+// syntax re-writes to inject hidden symbols.
+class DeclarationExp : public Expression
+{
+public:
+    Dsymbol *declaration;
+
+    DeclarationExp(Loc loc, Dsymbol *declaration);
+    Expression *syntaxCopy();
+
+    bool hasCode();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeidExp : public Expression
+{
+public:
+    RootObject *obj;
+
+    TypeidExp(Loc loc, RootObject *obj);
+    Expression *syntaxCopy();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TraitsExp : public Expression
+{
+public:
+    Identifier *ident;
+    Objects *args;
+
+    TraitsExp(Loc loc, Identifier *ident, Objects *args);
+    Expression *syntaxCopy();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class HaltExp : public Expression
+{
+public:
+    HaltExp(Loc loc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class IsExp : public Expression
+{
+public:
+    /* is(targ id tok tspec)
+     * is(targ id == tok2)
+     */
+    Type *targ;
+    Identifier *id;     // can be NULL
+    TOK tok;       // ':' or '=='
+    Type *tspec;        // can be NULL
+    TOK tok2;      // 'struct', 'union', etc.
+    TemplateParameters *parameters;
+
+    IsExp(Loc loc, Type *targ, Identifier *id, TOK tok, Type *tspec,
+        TOK tok2, TemplateParameters *parameters);
+    Expression *syntaxCopy();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+class UnaExp : public Expression
+{
+public:
+    Expression *e1;
+    Type *att1; // Save alias this type to detect recursion
+
+    UnaExp(Loc loc, TOK op, int size, Expression *e1);
+    Expression *syntaxCopy();
+    Expression *incompatibleTypes();
+    Expression *resolveLoc(Loc loc, Scope *sc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+typedef UnionExp (*fp_t)(Type *, Expression *, Expression *);
+typedef int (*fp2_t)(Loc loc, TOK, Expression *, Expression *);
+
+class BinExp : public Expression
+{
+public:
+    Expression *e1;
+    Expression *e2;
+
+    Type *att1; // Save alias this type to detect recursion
+    Type *att2; // Save alias this type to detect recursion
+
+    BinExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2);
+    Expression *syntaxCopy();
+    Expression *incompatibleTypes();
+    Expression *checkOpAssignTypes(Scope *sc);
+    bool checkIntegralBin();
+    bool checkArithmeticBin();
+
+    Expression *reorderSettingAAElem(Scope *sc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class BinAssignExp : public BinExp
+{
+public:
+    BinAssignExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2);
+
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *ex);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+class CompileExp : public UnaExp
+{
+public:
+    CompileExp(Loc loc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ImportExp : public UnaExp
+{
+public:
+    ImportExp(Loc loc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class AssertExp : public UnaExp
+{
+public:
+    Expression *msg;
+
+    AssertExp(Loc loc, Expression *e, Expression *msg = NULL);
+    Expression *syntaxCopy();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DotIdExp : public UnaExp
+{
+public:
+    Identifier *ident;
+    bool noderef;       // true if the result of the expression will never be dereferenced
+    bool wantsym;       // do not replace Symbol with its initializer during semantic()
+
+    DotIdExp(Loc loc, Expression *e, Identifier *ident);
+    static DotIdExp *create(Loc loc, Expression *e, Identifier *ident);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DotTemplateExp : public UnaExp
+{
+public:
+    TemplateDeclaration *td;
+
+    DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DotVarExp : public UnaExp
+{
+public:
+    Declaration *var;
+    bool hasOverloads;
+
+    DotVarExp(Loc loc, Expression *e, Declaration *var, bool hasOverloads = true);
+    int checkModifiable(Scope *sc, int flag);
+    bool checkReadModifyWrite();
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DotTemplateInstanceExp : public UnaExp
+{
+public:
+    TemplateInstance *ti;
+
+    DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs);
+    DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti);
+    Expression *syntaxCopy();
+    bool findTempDecl(Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DelegateExp : public UnaExp
+{
+public:
+    FuncDeclaration *func;
+    bool hasOverloads;
+
+    DelegateExp(Loc loc, Expression *e, FuncDeclaration *func, bool hasOverloads = true);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DotTypeExp : public UnaExp
+{
+public:
+    Dsymbol *sym;               // symbol that represents a type
+
+    DotTypeExp(Loc loc, Expression *e, Dsymbol *sym);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class CallExp : public UnaExp
+{
+public:
+    Expressions *arguments;     // function arguments
+    FuncDeclaration *f;         // symbol to call
+    bool directcall;            // true if a virtual call is devirtualized
+    CallExp(Loc loc, Expression *e, Expressions *exps);
+    CallExp(Loc loc, Expression *e);
+    CallExp(Loc loc, Expression *e, Expression *earg1);
+    CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2);
+
+    static CallExp *create(Loc loc, Expression *e, Expressions *exps);
+    static CallExp *create(Loc loc, Expression *e);
+    static CallExp *create(Loc loc, Expression *e, Expression *earg1);
+
+    Expression *syntaxCopy();
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *addDtorHook(Scope *sc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class AddrExp : public UnaExp
+{
+public:
+    AddrExp(Loc loc, Expression *e);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class PtrExp : public UnaExp
+{
+public:
+    PtrExp(Loc loc, Expression *e);
+    PtrExp(Loc loc, Expression *e, Type *t);
+    int checkModifiable(Scope *sc, int flag);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class NegExp : public UnaExp
+{
+public:
+    NegExp(Loc loc, Expression *e);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class UAddExp : public UnaExp
+{
+public:
+    UAddExp(Loc loc, Expression *e);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ComExp : public UnaExp
+{
+public:
+    ComExp(Loc loc, Expression *e);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class NotExp : public UnaExp
+{
+public:
+    NotExp(Loc loc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DeleteExp : public UnaExp
+{
+public:
+    bool isRAII;
+    DeleteExp(Loc loc, Expression *e, bool isRAII);
+    Expression *toBoolean(Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class CastExp : public UnaExp
+{
+public:
+    // Possible to cast to one type while painting to another type
+    Type *to;                   // type to cast to
+    unsigned char mod;          // MODxxxxx
+
+    CastExp(Loc loc, Expression *e, Type *t);
+    CastExp(Loc loc, Expression *e, unsigned char mod);
+    Expression *syntaxCopy();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class VectorExp : public UnaExp
+{
+public:
+    TypeVector *to;             // the target vector type before semantic()
+    unsigned dim;               // number of elements in the vector
+
+    VectorExp(Loc loc, Expression *e, Type *t);
+    static VectorExp *create(Loc loc, Expression *e, Type *t);
+    Expression *syntaxCopy();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class SliceExp : public UnaExp
+{
+public:
+    Expression *upr;            // NULL if implicit 0
+    Expression *lwr;            // NULL if implicit [length - 1]
+    VarDeclaration *lengthVar;
+    bool upperIsInBounds;       // true if upr <= e1.length
+    bool lowerIsLessThanUpper;  // true if lwr <= upr
+
+    SliceExp(Loc loc, Expression *e1, IntervalExp *ie);
+    SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr);
+    Expression *syntaxCopy();
+    int checkModifiable(Scope *sc, int flag);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    bool isBool(bool result);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ArrayLengthExp : public UnaExp
+{
+public:
+    ArrayLengthExp(Loc loc, Expression *e1);
+
+    static Expression *rewriteOpAssign(BinExp *exp);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class IntervalExp : public Expression
+{
+public:
+    Expression *lwr;
+    Expression *upr;
+
+    IntervalExp(Loc loc, Expression *lwr, Expression *upr);
+    Expression *syntaxCopy();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DelegatePtrExp : public UnaExp
+{
+public:
+    DelegatePtrExp(Loc loc, Expression *e1);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DelegateFuncptrExp : public UnaExp
+{
+public:
+    DelegateFuncptrExp(Loc loc, Expression *e1);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// e1[a0,a1,a2,a3,...]
+
+class ArrayExp : public UnaExp
+{
+public:
+    Expressions *arguments;             // Array of Expression's
+    size_t currentDimension;            // for opDollar
+    VarDeclaration *lengthVar;
+
+    ArrayExp(Loc loc, Expression *e1, Expression *index = NULL);
+    ArrayExp(Loc loc, Expression *e1, Expressions *args);
+    Expression *syntaxCopy();
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+class DotExp : public BinExp
+{
+public:
+    DotExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class CommaExp : public BinExp
+{
+public:
+    bool isGenerated;
+    bool allowCommaExp;
+    CommaExp(Loc loc, Expression *e1, Expression *e2, bool generated = true);
+    int checkModifiable(Scope *sc, int flag);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    bool isBool(bool result);
+    Expression *toBoolean(Scope *sc);
+    Expression *addDtorHook(Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class IndexExp : public BinExp
+{
+public:
+    VarDeclaration *lengthVar;
+    bool modifiable;
+    bool indexIsInBounds;       // true if 0 <= e2 && e2 <= e1.length - 1
+
+    IndexExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *syntaxCopy();
+    int checkModifiable(Scope *sc, int flag);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+
+    Expression *markSettingAAElem();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/* For both i++ and i--
+ */
+class PostExp : public BinExp
+{
+public:
+    PostExp(TOK op, Loc loc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/* For both ++i and --i
+ */
+class PreExp : public UnaExp
+{
+public:
+    PreExp(TOK op, Loc loc, Expression *e);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+enum MemorySet
+{
+    blockAssign     = 1,    // setting the contents of an array
+    referenceInit   = 2,    // setting the reference of STCref variable
+};
+
+class AssignExp : public BinExp
+{
+public:
+    int memset;         // combination of MemorySet flags
+
+    AssignExp(Loc loc, Expression *e1, Expression *e2);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *ex);
+    Expression *toBoolean(Scope *sc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ConstructExp : public AssignExp
+{
+public:
+    ConstructExp(Loc loc, Expression *e1, Expression *e2);
+    ConstructExp(Loc loc, VarDeclaration *v, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class BlitExp : public AssignExp
+{
+public:
+    BlitExp(Loc loc, Expression *e1, Expression *e2);
+    BlitExp(Loc loc, VarDeclaration *v, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class AddAssignExp : public BinAssignExp
+{
+public:
+    AddAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class MinAssignExp : public BinAssignExp
+{
+public:
+    MinAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class MulAssignExp : public BinAssignExp
+{
+public:
+    MulAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DivAssignExp : public BinAssignExp
+{
+public:
+    DivAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ModAssignExp : public BinAssignExp
+{
+public:
+    ModAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class AndAssignExp : public BinAssignExp
+{
+public:
+    AndAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class OrAssignExp : public BinAssignExp
+{
+public:
+    OrAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class XorAssignExp : public BinAssignExp
+{
+public:
+    XorAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class PowAssignExp : public BinAssignExp
+{
+public:
+    PowAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ShlAssignExp : public BinAssignExp
+{
+public:
+    ShlAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ShrAssignExp : public BinAssignExp
+{
+public:
+    ShrAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class UshrAssignExp : public BinAssignExp
+{
+public:
+    UshrAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class CatAssignExp : public BinAssignExp
+{
+public:
+    CatAssignExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class AddExp : public BinExp
+{
+public:
+    AddExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class MinExp : public BinExp
+{
+public:
+    MinExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class CatExp : public BinExp
+{
+public:
+    CatExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class MulExp : public BinExp
+{
+public:
+    MulExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DivExp : public BinExp
+{
+public:
+    DivExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ModExp : public BinExp
+{
+public:
+    ModExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class PowExp : public BinExp
+{
+public:
+    PowExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ShlExp : public BinExp
+{
+public:
+    ShlExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ShrExp : public BinExp
+{
+public:
+    ShrExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class UshrExp : public BinExp
+{
+public:
+    UshrExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class AndExp : public BinExp
+{
+public:
+    AndExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class OrExp : public BinExp
+{
+public:
+    OrExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class XorExp : public BinExp
+{
+public:
+    XorExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class OrOrExp : public BinExp
+{
+public:
+    OrOrExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *toBoolean(Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class AndAndExp : public BinExp
+{
+public:
+    AndAndExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *toBoolean(Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class CmpExp : public BinExp
+{
+public:
+    CmpExp(TOK op, Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class InExp : public BinExp
+{
+public:
+    InExp(Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class RemoveExp : public BinExp
+{
+public:
+    RemoveExp(Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// == and !=
+
+class EqualExp : public BinExp
+{
+public:
+    EqualExp(TOK op, Loc loc, Expression *e1, Expression *e2);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// is and !is
+
+class IdentityExp : public BinExp
+{
+public:
+    IdentityExp(TOK op, Loc loc, Expression *e1, Expression *e2);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+class CondExp : public BinExp
+{
+public:
+    Expression *econd;
+
+    CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2);
+    Expression *syntaxCopy();
+    int checkModifiable(Scope *sc, int flag);
+    bool isLvalue();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    Expression *toBoolean(Scope *sc);
+    void hookDtors(Scope *sc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+class DefaultInitExp : public Expression
+{
+public:
+    TOK subop;             // which of the derived classes this is
+
+    DefaultInitExp(Loc loc, TOK subop, int size);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class FileInitExp : public DefaultInitExp
+{
+public:
+    FileInitExp(Loc loc, TOK tok);
+    Expression *resolveLoc(Loc loc, Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class LineInitExp : public DefaultInitExp
+{
+public:
+    LineInitExp(Loc loc);
+    Expression *resolveLoc(Loc loc, Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ModuleInitExp : public DefaultInitExp
+{
+public:
+    ModuleInitExp(Loc loc);
+    Expression *resolveLoc(Loc loc, Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class FuncInitExp : public DefaultInitExp
+{
+public:
+    FuncInitExp(Loc loc);
+    Expression *resolveLoc(Loc loc, Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class PrettyFuncInitExp : public DefaultInitExp
+{
+public:
+    PrettyFuncInitExp(Loc loc);
+    Expression *resolveLoc(Loc loc, Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+/* A type meant as a union of all the Expression types,
+ * to serve essentially as a Variant that will sit on the stack
+ * during CTFE to reduce memory consumption.
+ */
+struct UnionExp
+{
+    UnionExp() { }  // yes, default constructor does nothing
+
+    UnionExp(Expression *e)
+    {
+        memcpy(this, (void *)e, e->size);
+    }
+
+    /* Extract pointer to Expression
+     */
+    Expression *exp() { return (Expression *)&u; }
+
+    /* Convert to an allocated Expression
+     */
+    Expression *copy();
+
+private:
+    union
+    {
+        char exp       [sizeof(Expression)];
+        char integerexp[sizeof(IntegerExp)];
+        char errorexp  [sizeof(ErrorExp)];
+        char realexp   [sizeof(RealExp)];
+        char complexexp[sizeof(ComplexExp)];
+        char symoffexp [sizeof(SymOffExp)];
+        char stringexp [sizeof(StringExp)];
+        char arrayliteralexp [sizeof(ArrayLiteralExp)];
+        char assocarrayliteralexp [sizeof(AssocArrayLiteralExp)];
+        char structliteralexp [sizeof(StructLiteralExp)];
+        char nullexp   [sizeof(NullExp)];
+        char dotvarexp [sizeof(DotVarExp)];
+        char addrexp   [sizeof(AddrExp)];
+        char indexexp  [sizeof(IndexExp)];
+        char sliceexp  [sizeof(SliceExp)];
+
+        // Ensure that the union is suitably aligned.
+        real_t for_alignment_only;
+    } u;
+};
+
+/****************************************************************/
+
+/* Special values used by the interpreter
+ */
+
+Expression *expType(Type *type, Expression *e);
+
+UnionExp Neg(Type *type, Expression *e1);
+UnionExp Com(Type *type, Expression *e1);
+UnionExp Not(Type *type, Expression *e1);
+UnionExp Bool(Type *type, Expression *e1);
+UnionExp Cast(Type *type, Type *to, Expression *e1);
+UnionExp ArrayLength(Type *type, Expression *e1);
+UnionExp Ptr(Type *type, Expression *e1);
+
+UnionExp Add(Type *type, Expression *e1, Expression *e2);
+UnionExp Min(Type *type, Expression *e1, Expression *e2);
+UnionExp Mul(Type *type, Expression *e1, Expression *e2);
+UnionExp Div(Type *type, Expression *e1, Expression *e2);
+UnionExp Mod(Type *type, Expression *e1, Expression *e2);
+UnionExp Pow(Type *type, Expression *e1, Expression *e2);
+UnionExp Shl(Type *type, Expression *e1, Expression *e2);
+UnionExp Shr(Type *type, Expression *e1, Expression *e2);
+UnionExp Ushr(Type *type, Expression *e1, Expression *e2);
+UnionExp And(Type *type, Expression *e1, Expression *e2);
+UnionExp Or(Type *type, Expression *e1, Expression *e2);
+UnionExp Xor(Type *type, Expression *e1, Expression *e2);
+UnionExp Index(Type *type, Expression *e1, Expression *e2);
+UnionExp Cat(Type *type, Expression *e1, Expression *e2);
+
+UnionExp Equal(TOK op, Type *type, Expression *e1, Expression *e2);
+UnionExp Cmp(TOK op, Type *type, Expression *e1, Expression *e2);
+UnionExp Identity(TOK op, Type *type, Expression *e1, Expression *e2);
+
+UnionExp Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr);
+
+// Const-folding functions used by CTFE
+
+void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, size_t firstIndex);
+void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, size_t firstIndex);
+void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, size_t firstIndex);
+
+int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len);
+int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len);
+
+
+#endif /* DMD_EXPRESSION_H */
diff --git a/gcc/d/dfrontend/expressionsem.c b/gcc/d/dfrontend/expressionsem.c
new file mode 100644
index 00000000000..b13da673c16
--- /dev/null
+++ b/gcc/d/dfrontend/expressionsem.c
@@ -0,0 +1,8840 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2017 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+#include <assert.h>
+
+#include "rmem.h"
+#include "root.h"
+
+#include "mtype.h"
+#include "init.h"
+#include "expression.h"
+#include "template.h"
+#include "utf.h"
+#include "enum.h"
+#include "scope.h"
+#include "statement.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "import.h"
+#include "id.h"
+#include "dsymbol.h"
+#include "module.h"
+#include "attrib.h"
+#include "hdrgen.h"
+#include "parse.h"
+#include "nspace.h"
+#include "ctfe.h"
+#include "target.h"
+
+bool typeMerge(Scope *sc, TOK op, Type **pt, Expression **pe1, Expression **pe2);
+bool isArrayOpValid(Expression *e);
+Expression *expandVar(int result, VarDeclaration *v);
+TypeTuple *toArgTypes(Type *t);
+bool checkAssignEscape(Scope *sc, Expression *e, bool gag);
+bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag);
+bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember);
+bool checkNestedRef(Dsymbol *s, Dsymbol *p);
+bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t istart = 0);
+bool symbolIsVisible(Module *mod, Dsymbol *s);
+VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
+Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
+Type *getTypeInfoType(Type *t, Scope *sc);
+bool MODimplicitConv(MOD modfrom, MOD modto);
+
+void unSpeculative(Scope *sc, RootObject *o);
+bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt);
+bool checkDefCtor(Loc loc, Type *t);
+bool isDotOpDispatch(Expression *e);
+bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix);
+bool preFunctionParameters(Loc loc, Scope *sc, Expressions *exps);
+Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, Expression *e1, Declaration *var, int flag = 0);
+bool isNeedThisScope(Scope *sc, Declaration *d);
+Expression *resolveUFCS(Scope *sc, CallExp *ce);
+bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
+FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
+
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL);
+Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL);
+Expression *trySemantic(Expression *e, Scope *sc);
+Expression *unaSemantic(UnaExp *e, Scope *sc);
+Expression *binSemantic(BinExp *e, Scope *sc);
+Expression *binSemanticProp(BinExp *e, Scope *sc);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
+Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
+
+#define LOGSEMANTIC     0
+
+class ExpressionSemanticVisitor : public Visitor
+{
+public:
+    Expression *result;
+    Scope *sc;
+
+    ExpressionSemanticVisitor(Scope *sc)
+    {
+        this->result = NULL;
+        this->sc = sc;
+    }
+
+private:
+    void setError()
+    {
+        result = new ErrorExp();
+    }
+
+    /*********************
+     * Mark the operand as will never be dereferenced,
+     * which is useful info for @safe checks.
+     * Do before semantic() on operands rewrites them.
+     */
+    static void setNoderefOperand(UnaExp *e)
+    {
+        if (e->e1->op == TOKdotid)
+            ((DotIdExp *)e->e1)->noderef = true;
+    }
+
+    /*********************
+     * Mark the operands as will never be dereferenced,
+     * which is useful info for @safe checks.
+     * Do before semantic() on operands rewrites them.
+     */
+    static void setNoderefOperands(BinExp *e)
+    {
+        if (e->e1->op == TOKdotid)
+            ((DotIdExp *)e->e1)->noderef = true;
+        if (e->e2->op == TOKdotid)
+            ((DotIdExp *)e->e2)->noderef = true;
+    }
+
+    static FuncDeclaration *resolveOverloadSet(Loc loc, Scope *sc,
+        OverloadSet *os, Objects* tiargs, Type *tthis, Expressions *arguments)
+    {
+        FuncDeclaration *f = NULL;
+        for (size_t i = 0; i < os->a.dim; i++)
+        {
+            Dsymbol *s = os->a[i];
+            if (tiargs && s->isFuncDeclaration())
+                continue;
+            if (FuncDeclaration *f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, 1))
+            {
+                if (f2->errors)
+                    return NULL;
+                if (f)
+                {
+                    /* Error if match in more than one overload set,
+                     * even if one is a 'better' match than the other.
+                     */
+                    ScopeDsymbol::multiplyDefined(loc, f, f2);
+                }
+                else
+                    f = f2;
+            }
+        }
+        if (!f)
+            ::error(loc, "no overload matches for %s", os->toChars());
+        else if (f->errors)
+            f = NULL;
+        return f;
+    }
+
+    static bool checkAddressVar(Scope *sc, AddrExp *e, VarDeclaration *v)
+    {
+        if (v)
+        {
+            if (!v->canTakeAddressOf())
+            {
+                e->error("cannot take address of %s", e->e1->toChars());
+                return false;
+            }
+            if (sc->func && !sc->intypeof && !v->isDataseg())
+            {
+                const char *p = v->isParameter() ? "parameter" : "local";
+                if (global.params.vsafe)
+                {
+                    // Taking the address of v means it cannot be set to 'scope' later
+                    v->storage_class &= ~STCmaybescope;
+                    v->doNotInferScope = true;
+                    if (v->storage_class & STCscope && sc->func->setUnsafe())
+                    {
+                        e->error("cannot take address of scope %s %s in @safe function %s", p, v->toChars(), sc->func->toChars());
+                        return false;
+                    }
+                }
+                else if (sc->func->setUnsafe())
+                {
+                    e->error("cannot take address of %s %s in @safe function %s", p, v->toChars(), sc->func->toChars());
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    static bool checkVectorElem(Expression *e, Expression *elem)
+    {
+        if (elem->isConst() == 1)
+            return false;
+
+        e->error("constant expression expected, not %s", elem->toChars());
+        return true;
+    }
+
+public:
+    void visit(Expression *e)
+    {
+#if LOGSEMANTIC
+        printf("Expression::semantic() %s\n", e->toChars());
+#endif
+        if (e->type)
+            e->type = e->type->semantic(e->loc, sc);
+        else
+            e->type = Type::tvoid;
+        result = e;
+    }
+
+    void visit(IntegerExp *e)
+    {
+        assert(e->type);
+        if (e->type->ty == Terror)
+            return setError();
+        assert(e->type->deco);
+        e->normalize();
+        result = e;
+    }
+
+    void visit(RealExp *e)
+    {
+        if (!e->type)
+            e->type = Type::tfloat64;
+        else
+            e->type = e->type->semantic(e->loc, sc);
+        result = e;
+    }
+
+    void visit(ComplexExp *e)
+    {
+        if (!e->type)
+            e->type = Type::tcomplex80;
+        else
+            e->type = e->type->semantic(e->loc, sc);
+        result = e;
+    }
+
+    void visit(IdentifierExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("IdentifierExp::semantic('%s')\n", exp->ident->toChars());
+#endif
+        if (exp->type)   // This is used as the dummy expression
+        {
+            result = exp;
+            return;
+        }
+
+        Dsymbol *scopesym;
+        Dsymbol *s = sc->search(exp->loc, exp->ident, &scopesym);
+        if (s)
+        {
+            if (s->errors)
+                return setError();
+
+            Expression *e;
+
+            /* See if the symbol was a member of an enclosing 'with'
+            */
+            WithScopeSymbol *withsym = scopesym->isWithScopeSymbol();
+            if (withsym && withsym->withstate->wthis)
+            {
+                /* Disallow shadowing
+                */
+                // First find the scope of the with
+                Scope *scwith = sc;
+                while (scwith->scopesym != scopesym)
+                {
+                    scwith = scwith->enclosing;
+                    assert(scwith);
+                }
+                // Look at enclosing scopes for symbols with the same name,
+                // in the same function
+                for (Scope *scx = scwith; scx && scx->func == scwith->func; scx = scx->enclosing)
+                {
+                    Dsymbol *s2;
+                    if (scx->scopesym && scx->scopesym->symtab &&
+                        (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL &&
+                        s != s2)
+                    {
+                        exp->error("with symbol %s is shadowing local symbol %s", s->toPrettyChars(), s2->toPrettyChars());
+                        return setError();
+                    }
+                }
+                s = s->toAlias();
+
+                // Same as wthis.ident
+                if (s->needThis() || s->isTemplateDeclaration())
+                {
+                    e = new VarExp(exp->loc, withsym->withstate->wthis);
+                    e = new DotIdExp(exp->loc, e, exp->ident);
+                }
+                else
+                {
+                    Type *t = withsym->withstate->wthis->type;
+                    if (t->ty == Tpointer)
+                        t = ((TypePointer *)t)->next;
+                    e = typeDotIdExp(exp->loc, t, exp->ident);
+                }
+                e = semantic(e, sc);
+            }
+            else
+            {
+                if (withsym)
+                {
+                    Declaration *d = s->isDeclaration();
+                    if (d)
+                        checkAccess(exp->loc, sc, NULL, d);
+                }
+
+                /* If f is really a function template,
+                 * then replace f with the function template declaration.
+                 */
+                FuncDeclaration *f = s->isFuncDeclaration();
+                if (f)
+                {
+                    TemplateDeclaration *td = getFuncTemplateDecl(f);
+                    if (td)
+                    {
+                        if (td->overroot)       // if not start of overloaded list of TemplateDeclaration's
+                            td = td->overroot;  // then get the start
+                        e = new TemplateExp(exp->loc, td, f);
+                        e = semantic(e, sc);
+                        result = e;
+                        return;
+                    }
+                }
+                // Haven't done overload resolution yet, so pass 1
+                e = resolve(exp->loc, sc, s, true);
+            }
+            result = e;
+            return;
+        }
+
+        if (hasThis(sc))
+        {
+            AggregateDeclaration *ad = sc->getStructClassScope();
+            if (ad && ad->aliasthis)
+            {
+                Expression *e;
+                e = new IdentifierExp(exp->loc, Id::This);
+                e = new DotIdExp(exp->loc, e, ad->aliasthis->ident);
+                e = new DotIdExp(exp->loc, e, exp->ident);
+                e = trySemantic(e, sc);
+                if (e)
+                {
+                    result = e;
+                    return;
+                }
+            }
+        }
+
+        if (exp->ident == Id::ctfe)
+        {
+            if (sc->flags & SCOPEctfe)
+            {
+                exp->error("variable __ctfe cannot be read at compile time");
+                return setError();
+            }
+
+            // Create the magic __ctfe bool variable
+            VarDeclaration *vd = new VarDeclaration(exp->loc, Type::tbool, Id::ctfe, NULL);
+            vd->storage_class |= STCtemp;
+            Expression *e = new VarExp(exp->loc, vd);
+            e = semantic(e, sc);
+            result = e;
+            return;
+        }
+
+        const char *n = importHint(exp->ident->toChars());
+        if (n)
+            exp->error("'%s' is not defined, perhaps you need to import %s; ?", exp->ident->toChars(), n);
+        else
+        {
+            s = sc->search_correct(exp->ident);
+            if (s)
+                exp->error("undefined identifier '%s', did you mean %s '%s'?", exp->ident->toChars(), s->kind(), s->toChars());
+            else
+                exp->error("undefined identifier '%s'", exp->ident->toChars());
+        }
+        return setError();
+    }
+
+    void visit(DsymbolExp *e)
+    {
+        result = resolve(e->loc, sc, e->s, e->hasOverloads);
+    }
+
+    void visit(ThisExp *e)
+    {
+#if LOGSEMANTIC
+        printf("ThisExp::semantic()\n");
+#endif
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+
+        FuncDeclaration *fd = hasThis(sc);  // fd is the uplevel function with the 'this' variable
+
+        /* Special case for typeof(this) and typeof(super) since both
+         * should work even if they are not inside a non-static member function
+         */
+        if (!fd && sc->intypeof == 1)
+        {
+            // Find enclosing struct or class
+            for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent)
+            {
+                if (!s)
+                {
+                    e->error("%s is not in a class or struct scope", e->toChars());
+                    goto Lerr;
+                }
+                ClassDeclaration *cd = s->isClassDeclaration();
+                if (cd)
+                {
+                    e->type = cd->type;
+                    result = e;
+                    return;
+                }
+                StructDeclaration *sd = s->isStructDeclaration();
+                if (sd)
+                {
+                    e->type = sd->type;
+                    result = e;
+                    return;
+                }
+            }
+        }
+        if (!fd)
+            goto Lerr;
+
+        assert(fd->vthis);
+        e->var = fd->vthis;
+        assert(e->var->parent);
+        e->type = e->var->type;
+        if (e->var->checkNestedReference(sc, e->loc))
+            return setError();
+        if (!sc->intypeof)
+            sc->callSuper |= CSXthis;
+        result = e;
+        return;
+
+    Lerr:
+        e->error("'this' is only defined in non-static member functions, not %s", sc->parent->toChars());
+        return setError();
+    }
+
+    void visit(SuperExp *e)
+    {
+#if LOGSEMANTIC
+        printf("SuperExp::semantic('%s')\n", e->toChars());
+#endif
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+
+        FuncDeclaration *fd = hasThis(sc);
+        ClassDeclaration *cd;
+        Dsymbol *s;
+
+        /* Special case for typeof(this) and typeof(super) since both
+         * should work even if they are not inside a non-static member function
+         */
+        if (!fd && sc->intypeof == 1)
+        {
+            // Find enclosing class
+            for (s = sc->getStructClassScope(); 1; s = s->parent)
+            {
+                if (!s)
+                {
+                    e->error("%s is not in a class scope", e->toChars());
+                    goto Lerr;
+                }
+                cd = s->isClassDeclaration();
+                if (cd)
+                {
+                    cd = cd->baseClass;
+                    if (!cd)
+                    {
+                        e->error("class %s has no 'super'", s->toChars());
+                        goto Lerr;
+                    }
+                    e->type = cd->type;
+                    result = e;
+                    return;
+                }
+            }
+        }
+        if (!fd)
+            goto Lerr;
+
+        e->var = fd->vthis;
+        assert(e->var && e->var->parent);
+
+        s = fd->toParent();
+        while (s && s->isTemplateInstance())
+            s = s->toParent();
+        if (s->isTemplateDeclaration()) // allow inside template constraint
+            s = s->toParent();
+        assert(s);
+        cd = s->isClassDeclaration();
+        //printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars());
+        if (!cd)
+            goto Lerr;
+        if (!cd->baseClass)
+        {
+            e->error("no base class for %s", cd->toChars());
+            e->type = e->var->type;
+        }
+        else
+        {
+            e->type = cd->baseClass->type;
+            e->type = e->type->castMod(e->var->type->mod);
+        }
+
+        if (e->var->checkNestedReference(sc, e->loc))
+            return setError();
+
+        if (!sc->intypeof)
+            sc->callSuper |= CSXsuper;
+        result = e;
+        return;
+
+    Lerr:
+        e->error("'super' is only allowed in non-static class member functions");
+        return setError();
+    }
+
+    void visit(NullExp *e)
+    {
+#if LOGSEMANTIC
+        printf("NullExp::semantic('%s')\n", e->toChars());
+#endif
+        // NULL is the same as (void *)0
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+        e->type = Type::tnull;
+        result = e;
+    }
+
+    void visit(StringExp *e)
+    {
+#if LOGSEMANTIC
+        printf("StringExp::semantic() %s\n", e->toChars());
+#endif
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+
+        OutBuffer buffer;
+        size_t newlen = 0;
+        const char *p;
+        size_t u;
+        unsigned c;
+
+        switch (e->postfix)
+        {
+            case 'd':
+                for (u = 0; u < e->len;)
+                {
+                    p = utf_decodeChar((utf8_t *)e->string, e->len, &u, &c);
+                    if (p)
+                    {
+                        e->error("%s", p);
+                        return setError();
+                    }
+                    else
+                    {
+                        buffer.write4(c);
+                        newlen++;
+                    }
+                }
+                buffer.write4(0);
+                e->string = buffer.extractData();
+                e->len = newlen;
+                e->sz = 4;
+                e->type = new TypeDArray(Type::tdchar->immutableOf());
+                e->committed = 1;
+                break;
+
+            case 'w':
+                for (u = 0; u < e->len;)
+                {
+                    p = utf_decodeChar((utf8_t *)e->string, e->len, &u, &c);
+                    if (p)
+                    {
+                        e->error("%s", p);
+                        return setError();
+                    }
+                    else
+                    {
+                        buffer.writeUTF16(c);
+                        newlen++;
+                        if (c >= 0x10000)
+                            newlen++;
+                    }
+                }
+                buffer.writeUTF16(0);
+                e->string = buffer.extractData();
+                e->len = newlen;
+                e->sz = 2;
+                e->type = new TypeDArray(Type::twchar->immutableOf());
+                e->committed = 1;
+                break;
+
+            case 'c':
+                e->committed = 1;
+            default:
+                e->type = new TypeDArray(Type::tchar->immutableOf());
+                break;
+        }
+        e->type = e->type->semantic(e->loc, sc);
+        //e->type = e->type->immutableOf();
+        //printf("type = %s\n", e->type->toChars());
+
+        result = e;
+    }
+
+    void visit(ArrayLiteralExp *e)
+    {
+#if LOGSEMANTIC
+        printf("ArrayLiteralExp::semantic('%s')\n", e->toChars());
+#endif
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+
+        /* Perhaps an empty array literal [ ] should be rewritten as null?
+        */
+
+        if (e->basis)
+            e->basis = semantic(e->basis, sc);
+        if (arrayExpressionSemantic(e->elements, sc) || (e->basis && e->basis->op == TOKerror))
+            return setError();
+        expandTuples(e->elements);
+
+        Type *t0;
+        if (e->basis)
+            e->elements->push(e->basis);
+        bool err = arrayExpressionToCommonType(sc, e->elements, &t0);
+        if (e->basis)
+            e->elements->pop();
+        if (err)
+            return setError();
+
+        e->type = t0->arrayOf();
+        e->type = e->type->semantic(e->loc, sc);
+
+        /* Disallow array literals of type void being used.
+        */
+        if (e->elements->dim > 0 && t0->ty == Tvoid)
+        {
+            e->error("%s of type %s has no value", e->toChars(), e->type->toChars());
+            return setError();
+        }
+
+        semanticTypeInfo(sc, e->type);
+
+        result = e;
+    }
+
+    void visit(AssocArrayLiteralExp *e)
+    {
+#if LOGSEMANTIC
+        printf("AssocArrayLiteralExp::semantic('%s')\n", e->toChars());
+#endif
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+
+        // Run semantic() on each element
+        bool err_keys = arrayExpressionSemantic(e->keys, sc);
+        bool err_vals = arrayExpressionSemantic(e->values, sc);
+        if (err_keys || err_vals)
+            return setError();
+        expandTuples(e->keys);
+        expandTuples(e->values);
+        if (e->keys->dim != e->values->dim)
+        {
+            e->error("number of keys is %u, must match number of values %u", e->keys->dim, e->values->dim);
+            return setError();
+        }
+
+        Type *tkey = NULL;
+        Type *tvalue = NULL;
+        err_keys = arrayExpressionToCommonType(sc, e->keys, &tkey);
+        err_vals = arrayExpressionToCommonType(sc, e->values, &tvalue);
+        if (err_keys || err_vals)
+            return setError();
+
+        if (tkey == Type::terror || tvalue == Type::terror)
+            return setError();
+
+        e->type = new TypeAArray(tvalue, tkey);
+        e->type = e->type->semantic(e->loc, sc);
+
+        semanticTypeInfo(sc, e->type);
+
+        result = e;
+    }
+
+    void visit(StructLiteralExp *e)
+    {
+#if LOGSEMANTIC
+        printf("StructLiteralExp::semantic('%s')\n", e->toChars());
+#endif
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+
+        e->sd->size(e->loc);
+        if (e->sd->sizeok != SIZEOKdone)
+            return setError();
+
+        if (arrayExpressionSemantic(e->elements, sc))  // run semantic() on each element
+            return setError();
+        expandTuples(e->elements);
+
+        /* Fit elements[] to the corresponding type of field[].
+        */
+        if (!e->sd->fit(e->loc, sc, e->elements, e->stype))
+            return setError();
+
+        /* Fill out remainder of elements[] with default initializers for fields[]
+        */
+        if (!e->sd->fill(e->loc, e->elements, false))
+        {
+            /* An error in the initializer needs to be recorded as an error
+             * in the enclosing function or template, since the initializer
+             * will be part of the stuct declaration.
+             */
+            global.increaseErrorCount();
+            return setError();
+        }
+
+        if (checkFrameAccess(e->loc, sc, e->sd, e->elements->dim))
+            return setError();
+
+        e->type = e->stype ? e->stype : e->sd->type;
+        result = e;
+    }
+
+    void visit(TypeExp *exp)
+    {
+        //printf("TypeExp::semantic(%s)\n", exp->type->toChars());
+        Expression *e;
+        Type *t;
+        Dsymbol *s;
+
+        exp->type->resolve(exp->loc, sc, &e, &t, &s, true);
+        if (e)
+        {
+            //printf("e = %s %s\n", Token::toChars(e->op), e->toChars());
+            e = semantic(e, sc);
+        }
+        else if (t)
+        {
+            //printf("t = %d %s\n", t->ty, t->toChars());
+            exp->type = t->semantic(exp->loc, sc);
+            e = exp;
+        }
+        else if (s)
+        {
+            //printf("s = %s %s\n", s->kind(), s->toChars());
+            e = resolve(exp->loc, sc, s, true);
+        }
+        else
+            assert(0);
+
+        if (global.params.vcomplex)
+            exp->type->checkComplexTransition(exp->loc);
+
+        result = e;
+    }
+
+    void visit(ScopeExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("+ScopeExp::semantic(%p '%s')\n", exp, exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        ScopeDsymbol *sds2 = exp->sds;
+        TemplateInstance *ti = sds2->isTemplateInstance();
+        while (ti)
+        {
+            WithScopeSymbol *withsym;
+            if (!ti->findTempDecl(sc, &withsym) ||
+                !ti->semanticTiargs(sc))
+                return setError();
+            if (withsym && withsym->withstate->wthis)
+            {
+                Expression *e = new VarExp(exp->loc, withsym->withstate->wthis);
+                e = new DotTemplateInstanceExp(exp->loc, e, ti);
+                result = semantic(e, sc);
+                return;
+            }
+            if (ti->needsTypeInference(sc))
+            {
+                if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration())
+                {
+                    Dsymbol *p = td->toParent2();
+                    FuncDeclaration *fdthis = hasThis(sc);
+                    AggregateDeclaration *ad = p ? p->isAggregateDeclaration() : NULL;
+                    if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad &&
+                        (td->_scope->stc & STCstatic) == 0)
+                    {
+                        Expression *e = new DotTemplateInstanceExp(exp->loc, new ThisExp(exp->loc), ti->name, ti->tiargs);
+                        result = semantic(e, sc);
+                        return;
+                    }
+                }
+                else if (OverloadSet *os = ti->tempdecl->isOverloadSet())
+                {
+                    FuncDeclaration *fdthis = hasThis(sc);
+                    AggregateDeclaration *ad = os->parent->isAggregateDeclaration();
+                    if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad)
+                    {
+                        Expression *e = new DotTemplateInstanceExp(exp->loc, new ThisExp(exp->loc), ti->name, ti->tiargs);
+                        result = semantic(e, sc);
+                        return;
+                    }
+                }
+                // ti is an instance which requires IFTI.
+                exp->sds = ti;
+                exp->type = Type::tvoid;
+                result = exp;
+                return;
+            }
+            ti->semantic(sc);
+            if (!ti->inst || ti->errors)
+                return setError();
+
+            Dsymbol *s = ti->toAlias();
+            if (s == ti)
+            {
+                exp->sds = ti;
+                exp->type = Type::tvoid;
+                result = exp;
+                return;
+            }
+            sds2 = s->isScopeDsymbol();
+            if (sds2)
+            {
+                ti = sds2->isTemplateInstance();
+                //printf("+ sds2 = %s, '%s'\n", sds2->kind(), sds2->toChars());
+                continue;
+            }
+
+            if (VarDeclaration *v = s->isVarDeclaration())
+            {
+                if (!v->type)
+                {
+                    exp->error("forward reference of %s %s", v->kind(), v->toChars());
+                    return setError();
+                }
+                if ((v->storage_class & STCmanifest) && v->_init)
+                {
+                    /* When an instance that will be converted to a constant exists,
+                     * the instance representation "foo!tiargs" is treated like a
+                     * variable name, and its recursive appearance check (note that
+                     * it's equivalent with a recursive instantiation of foo) is done
+                     * separately from the circular initialization check for the
+                     * eponymous enum variable declaration.
+                     *
+                     *  template foo(T) {
+                     *    enum bool foo = foo;    // recursive definition check (v.inuse)
+                     *  }
+                     *  template bar(T) {
+                     *    enum bool bar = bar!T;  // recursive instantiation check (ti.inuse)
+                     *  }
+                     */
+                    if (ti->inuse)
+                    {
+                        exp->error("recursive expansion of %s '%s'", ti->kind(), ti->toPrettyChars());
+                        return setError();
+                    }
+
+                    Expression *e = v->expandInitializer(exp->loc);
+                    ti->inuse++;
+                    e = semantic(e, sc);
+                    ti->inuse--;
+                    result = e;
+                    return;
+                }
+            }
+
+            //printf("s = %s, '%s'\n", s->kind(), s->toChars());
+            Expression *e = resolve(exp->loc, sc, s, true);
+            //printf("-1ScopeExp::semantic()\n");
+            result = e;
+            return;
+        }
+
+        //printf("sds2 = %s, '%s'\n", sds2->kind(), sds2->toChars());
+        //printf("\tparent = '%s'\n", sds2->parent->toChars());
+        sds2->semantic(sc);
+
+        if (Type *t = sds2->getType())    // (Aggregate|Enum)Declaration
+        {
+            Expression *ex = new TypeExp(exp->loc, t);
+            result = semantic(ex, sc);
+            return;
+        }
+
+        exp->sds = sds2;
+        exp->type = Type::tvoid;
+        //printf("-2ScopeExp::semantic() %s\n", exp->toChars());
+        result = exp;
+    }
+
+    void visit(NewExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("NewExp::semantic() %s\n", exp->toChars());
+        if (exp->thisexp)
+            printf("\tthisexp = %s\n", exp->thisexp->toChars());
+        printf("\tnewtype: %s\n", exp->newtype->toChars());
+#endif
+        if (exp->type)                   // if semantic() already run
+        {
+            result = exp;
+            return;
+        }
+
+        Type *tb;
+        ClassDeclaration *cdthis = NULL;
+        size_t nargs;
+        Expression *newprefix = NULL;
+
+    Lagain:
+        if (exp->thisexp)
+        {
+            exp->thisexp = semantic(exp->thisexp, sc);
+            cdthis = exp->thisexp->type->isClassHandle();
+            if (cdthis)
+            {
+                sc = sc->push(cdthis);
+                exp->type = exp->newtype->semantic(exp->loc, sc);
+                sc = sc->pop();
+
+                if (exp->type->ty == Terror)
+                    goto Lerr;
+                if (!MODimplicitConv(exp->thisexp->type->mod, exp->newtype->mod))
+                {
+                    exp->error("nested type %s should have the same or weaker constancy as enclosing type %s",
+                        exp->newtype->toChars(), exp->thisexp->type->toChars());
+                    goto Lerr;
+                }
+            }
+            else
+            {
+                exp->error("'this' for nested class must be a class type, not %s", exp->thisexp->type->toChars());
+                goto Lerr;
+            }
+        }
+        else
+        {
+            exp->type = exp->newtype->semantic(exp->loc, sc);
+            if (exp->type->ty == Terror)
+                goto Lerr;
+        }
+        exp->newtype = exp->type;             // in case type gets cast to something else
+        tb = exp->type->toBasetype();
+        //printf("tb: %s, deco = %s\n", tb->toChars(), tb->deco);
+
+        if (arrayExpressionSemantic(exp->newargs, sc) ||
+            preFunctionParameters(exp->loc, sc, exp->newargs))
+        {
+            goto Lerr;
+        }
+        if (arrayExpressionSemantic(exp->arguments, sc) ||
+            preFunctionParameters(exp->loc, sc, exp->arguments))
+        {
+            goto Lerr;
+        }
+
+        nargs = exp->arguments ? exp->arguments->dim : 0;
+
+        if (exp->thisexp && tb->ty != Tclass)
+        {
+            exp->error("e.new is only for allocating nested classes, not %s", tb->toChars());
+            goto Lerr;
+        }
+
+        if (tb->ty == Tclass)
+        {
+            ClassDeclaration *cd = ((TypeClass *)tb)->sym;
+            cd->size(exp->loc);
+            if (cd->sizeok != SIZEOKdone)
+                return setError();
+            if (!cd->ctor)
+                cd->ctor = cd->searchCtor();
+            if (cd->noDefaultCtor && !nargs && !cd->defaultCtor)
+            {
+                exp->error("default construction is disabled for type %s", cd->type->toChars());
+                goto Lerr;
+            }
+
+            if (cd->isInterfaceDeclaration())
+            {
+                exp->error("cannot create instance of interface %s", cd->toChars());
+                goto Lerr;
+            }
+            if (cd->isAbstract())
+            {
+                exp->error("cannot create instance of abstract class %s", cd->toChars());
+                for (size_t i = 0; i < cd->vtbl.dim; i++)
+                {
+                    FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration();
+                    if (fd && fd->isAbstract())
+                        errorSupplemental(exp->loc, "function '%s' is not implemented", fd->toFullSignature());
+                }
+                goto Lerr;
+            }
+            // checkDeprecated() is already done in newtype->semantic().
+
+            if (cd->isNested())
+            {
+                /* We need a 'this' pointer for the nested class.
+                 * Ensure we have the right one.
+                 */
+                Dsymbol *s = cd->toParent2();
+                ClassDeclaration *cdn = s->isClassDeclaration();
+                FuncDeclaration *fdn = s->isFuncDeclaration();
+
+                //printf("cd isNested, cdn = %s\n", cdn ? cdn->toChars() : "null");
+                if (cdn)
+                {
+                    if (!cdthis)
+                    {
+                        // Supply an implicit 'this' and try again
+                        exp->thisexp = new ThisExp(exp->loc);
+                        for (Dsymbol *sp = sc->parent; 1; sp = sp->parent)
+                        {
+                            if (!sp)
+                            {
+                                exp->error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars());
+                                goto Lerr;
+                            }
+                            ClassDeclaration *cdp = sp->isClassDeclaration();
+                            if (!cdp)
+                                continue;
+                            if (cdp == cdn || cdn->isBaseOf(cdp, NULL))
+                                break;
+                            // Add a '.outer' and try again
+                            exp->thisexp = new DotIdExp(exp->loc, exp->thisexp, Id::outer);
+                        }
+                        if (!global.errors)
+                            goto Lagain;
+                    }
+                    if (cdthis)
+                    {
+                        //printf("cdthis = %s\n", cdthis->toChars());
+                        if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL))
+                        {
+                            exp->error("'this' for nested class must be of type %s, not %s", cdn->toChars(), exp->thisexp->type->toChars());
+                            goto Lerr;
+                        }
+                    }
+                }
+                else if (exp->thisexp)
+                {
+                    exp->error("e.new is only for allocating nested classes");
+                    goto Lerr;
+                }
+                else if (fdn)
+                {
+                    // make sure the parent context fdn of cd is reachable from sc
+                    if (checkNestedRef(sc->parent, fdn))
+                    {
+                        exp->error("outer function context of %s is needed to 'new' nested class %s",
+                            fdn->toPrettyChars(), cd->toPrettyChars());
+                        goto Lerr;
+                    }
+                }
+                else
+                    assert(0);
+            }
+            else if (exp->thisexp)
+            {
+                exp->error("e.new is only for allocating nested classes");
+                goto Lerr;
+            }
+
+            if (cd->aggNew)
+            {
+                // Prepend the size argument to newargs[]
+                Expression *e = new IntegerExp(exp->loc, cd->size(exp->loc), Type::tsize_t);
+                if (!exp->newargs)
+                    exp->newargs = new Expressions();
+                exp->newargs->shift(e);
+
+                FuncDeclaration *f = resolveFuncCall(exp->loc, sc, cd->aggNew, NULL, tb, exp->newargs);
+                if (!f || f->errors)
+                    goto Lerr;
+                exp->checkDeprecated(sc, f);
+                exp->checkPurity(sc, f);
+                exp->checkSafety(sc, f);
+                exp->checkNogc(sc, f);
+                checkAccess(cd, exp->loc, sc, f);
+
+                TypeFunction *tf = (TypeFunction *)f->type;
+                Type *rettype;
+                if (functionParameters(exp->loc, sc, tf, NULL, exp->newargs, f, &rettype, &newprefix))
+                    return setError();
+
+                exp->allocator = f->isNewDeclaration();
+                assert(exp->allocator);
+            }
+            else
+            {
+                if (exp->newargs && exp->newargs->dim)
+                {
+                    exp->error("no allocator for %s", cd->toChars());
+                    goto Lerr;
+                }
+            }
+
+            if (cd->ctor)
+            {
+                FuncDeclaration *f = resolveFuncCall(exp->loc, sc, cd->ctor, NULL, tb, exp->arguments, 0);
+                if (!f || f->errors)
+                    goto Lerr;
+                exp->checkDeprecated(sc, f);
+                exp->checkPurity(sc, f);
+                exp->checkSafety(sc, f);
+                exp->checkNogc(sc, f);
+                checkAccess(cd, exp->loc, sc, f);
+
+                TypeFunction *tf = (TypeFunction *)f->type;
+                if (!exp->arguments)
+                    exp->arguments = new Expressions();
+                if (functionParameters(exp->loc, sc, tf, exp->type, exp->arguments, f, &exp->type, &exp->argprefix))
+                    return setError();
+
+                exp->member = f->isCtorDeclaration();
+                assert(exp->member);
+            }
+            else
+            {
+                if (nargs)
+                {
+                    exp->error("no constructor for %s", cd->toChars());
+                    goto Lerr;
+                }
+            }
+        }
+        else if (tb->ty == Tstruct)
+        {
+            StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+            sd->size(exp->loc);
+            if (sd->sizeok != SIZEOKdone)
+                return setError();
+            if (!sd->ctor)
+                sd->ctor = sd->searchCtor();
+            if (sd->noDefaultCtor && !nargs)
+            {
+                exp->error("default construction is disabled for type %s", sd->type->toChars());
+                goto Lerr;
+            }
+            // checkDeprecated() is already done in newtype->semantic().
+
+            if (sd->aggNew)
+            {
+                // Prepend the uint size argument to newargs[]
+                Expression *e = new IntegerExp(exp->loc, sd->size(exp->loc), Type::tsize_t);
+                if (!exp->newargs)
+                    exp->newargs = new Expressions();
+                exp->newargs->shift(e);
+
+                FuncDeclaration *f = resolveFuncCall(exp->loc, sc, sd->aggNew, NULL, tb, exp->newargs);
+                if (!f || f->errors)
+                    goto Lerr;
+                exp->checkDeprecated(sc, f);
+                exp->checkPurity(sc, f);
+                exp->checkSafety(sc, f);
+                exp->checkNogc(sc, f);
+                checkAccess(sd, exp->loc, sc, f);
+
+                TypeFunction *tf = (TypeFunction *)f->type;
+                Type *rettype;
+                if (functionParameters(exp->loc, sc, tf, NULL, exp->newargs, f, &rettype, &newprefix))
+                    return setError();
+
+                exp->allocator = f->isNewDeclaration();
+                assert(exp->allocator);
+            }
+            else
+            {
+                if (exp->newargs && exp->newargs->dim)
+                {
+                    exp->error("no allocator for %s", sd->toChars());
+                    goto Lerr;
+                }
+            }
+
+            if (sd->ctor && nargs)
+            {
+                FuncDeclaration *f = resolveFuncCall(exp->loc, sc, sd->ctor, NULL, tb, exp->arguments, 0);
+                if (!f || f->errors)
+                    goto Lerr;
+                exp->checkDeprecated(sc, f);
+                exp->checkPurity(sc, f);
+                exp->checkSafety(sc, f);
+                exp->checkNogc(sc, f);
+                checkAccess(sd, exp->loc, sc, f);
+
+                TypeFunction *tf = (TypeFunction *)f->type;
+                if (!exp->arguments)
+                    exp->arguments = new Expressions();
+                if (functionParameters(exp->loc, sc, tf, exp->type, exp->arguments, f, &exp->type, &exp->argprefix))
+                    return setError();
+
+                exp->member = f->isCtorDeclaration();
+                assert(exp->member);
+
+                if (checkFrameAccess(exp->loc, sc, sd, sd->fields.dim))
+                    return setError();
+            }
+            else
+            {
+                if (!exp->arguments)
+                    exp->arguments = new Expressions();
+
+                if (!sd->fit(exp->loc, sc, exp->arguments, tb))
+                    return setError();
+                if (!sd->fill(exp->loc, exp->arguments, false))
+                    return setError();
+                if (checkFrameAccess(exp->loc, sc, sd, exp->arguments ? exp->arguments->dim : 0))
+                    return setError();
+            }
+
+            exp->type = exp->type->pointerTo();
+        }
+        else if (tb->ty == Tarray && nargs)
+        {
+            Type *tn = tb->nextOf()->baseElemOf();
+            Dsymbol *s = tn->toDsymbol(sc);
+            AggregateDeclaration *ad = s ? s->isAggregateDeclaration() : NULL;
+            if (ad && ad->noDefaultCtor)
+            {
+                exp->error("default construction is disabled for type %s", tb->nextOf()->toChars());
+                goto Lerr;
+            }
+            for (size_t i = 0; i < nargs; i++)
+            {
+                if (tb->ty != Tarray)
+                {
+                    exp->error("too many arguments for array");
+                    goto Lerr;
+                }
+
+                Expression *arg = (*exp->arguments)[i];
+                arg = resolveProperties(sc, arg);
+                arg = arg->implicitCastTo(sc, Type::tsize_t);
+                arg = arg->optimize(WANTvalue);
+                if (arg->op == TOKint64 && (sinteger_t)arg->toInteger() < 0)
+                {
+                    exp->error("negative array index %s", arg->toChars());
+                    goto Lerr;
+                }
+                (*exp->arguments)[i] =  arg;
+                tb = ((TypeDArray *)tb)->next->toBasetype();
+            }
+        }
+        else if (tb->isscalar())
+        {
+            if (!nargs)
+            {
+            }
+            else if (nargs == 1)
+            {
+                Expression *e = (*exp->arguments)[0];
+                e = e->implicitCastTo(sc, tb);
+                (*exp->arguments)[0] = e;
+            }
+            else
+            {
+                exp->error("more than one argument for construction of %s", exp->type->toChars());
+                goto Lerr;
+            }
+
+            exp->type = exp->type->pointerTo();
+        }
+        else
+        {
+            exp->error("new can only create structs, dynamic arrays or class objects, not %s's", exp->type->toChars());
+            goto Lerr;
+        }
+
+        //printf("NewExp: '%s'\n", toChars());
+        //printf("NewExp:type '%s'\n", exp->type->toChars());
+        semanticTypeInfo(sc, exp->type);
+
+        if (newprefix)
+        {
+            result = Expression::combine(newprefix, exp);
+            return;
+        }
+        result = exp;
+        return;
+
+    Lerr:
+        return setError();
+    }
+
+    void visit(NewAnonClassExp *e)
+    {
+#if LOGSEMANTIC
+        printf("NewAnonClassExp::semantic() %s\n", e->toChars());
+        //printf("thisexp = %p\n", e->thisexp);
+        //printf("type: %s\n", e->type->toChars());
+#endif
+
+        Expression *d = new DeclarationExp(e->loc, e->cd);
+        sc = sc->push();            // just create new scope
+        sc->flags &= ~SCOPEctfe;    // temporary stop CTFE
+        d = semantic(d, sc);
+        sc = sc->pop();
+
+        if (!e->cd->errors && sc->intypeof && !sc->parent->inNonRoot())
+        {
+            ScopeDsymbol *sds = sc->tinst ? (ScopeDsymbol *)sc->tinst : sc->_module;
+            sds->members->push(e->cd);
+        }
+
+        Expression *n = new NewExp(e->loc, e->thisexp, e->newargs, e->cd->type, e->arguments);
+
+        Expression *c = new CommaExp(e->loc, d, n);
+        result = semantic(c, sc);
+    }
+
+    void visit(SymOffExp *e)
+    {
+#if LOGSEMANTIC
+        printf("SymOffExp::semantic('%s')\n", e->toChars());
+#endif
+        //var->semantic(sc);
+        if (!e->type)
+            e->type = e->var->type->pointerTo();
+        if (VarDeclaration *v = e->var->isVarDeclaration())
+        {
+            if (v->checkNestedReference(sc, e->loc))
+                return setError();
+        }
+        else if (FuncDeclaration *f = e->var->isFuncDeclaration())
+        {
+            if (f->checkNestedReference(sc, e->loc))
+                return setError();
+        }
+        result = e;
+    }
+
+    void visit(VarExp *e)
+    {
+#if LOGSEMANTIC
+        printf("VarExp::semantic(%s)\n", e->toChars());
+#endif
+        if (FuncDeclaration *fd = e->var->isFuncDeclaration())
+        {
+            //printf("L%d fd = %s\n", __LINE__, f->toChars());
+            if (!fd->functionSemantic())
+                return setError();
+        }
+
+        if (!e->type)
+            e->type = e->var->type;
+
+        if (e->type && !e->type->deco)
+            e->type = e->type->semantic(e->loc, sc);
+
+        /* Fix for 1161 doesn't work because it causes protection
+         * problems when instantiating imported templates passing private
+         * variables as alias template parameters.
+         */
+        //checkAccess(e->loc, sc, NULL, e->var);
+
+        if (VarDeclaration *vd = e->var->isVarDeclaration())
+        {
+            if (vd->checkNestedReference(sc, e->loc))
+                return setError();
+            // Bugzilla 12025: If the variable is not actually used in runtime code,
+            // the purity violation error is redundant.
+            //checkPurity(sc, vd);
+        }
+        else if (FuncDeclaration *fd = e->var->isFuncDeclaration())
+        {
+            // TODO: If fd isn't yet resolved its overload, the checkNestedReference
+            // call would cause incorrect validation.
+            // Maybe here should be moved in CallExp, or AddrExp for functions.
+            if (fd->checkNestedReference(sc, e->loc))
+                return setError();
+        }
+        else if (OverDeclaration *od = e->var->isOverDeclaration())
+        {
+            e->type = Type::tvoid; // ambiguous type?
+        }
+
+        result = e;
+    }
+
+    void visit(TupleExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("+TupleExp::semantic(%s)\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (exp->e0)
+            exp->e0 = semantic(exp->e0, sc);
+
+        // Run semantic() on each argument
+        bool err = false;
+        for (size_t i = 0; i < exp->exps->dim; i++)
+        {
+            Expression *e = (*exp->exps)[i];
+            e = semantic(e, sc);
+            if (!e->type)
+            {
+                exp->error("%s has no value", e->toChars());
+                err = true;
+            }
+            else if (e->op == TOKerror)
+                err = true;
+            else
+                (*exp->exps)[i] = e;
+        }
+        if (err)
+            return setError();
+
+        expandTuples(exp->exps);
+        exp->type = new TypeTuple(exp->exps);
+        exp->type = exp->type->semantic(exp->loc, sc);
+        //printf("-TupleExp::semantic(%s)\n", exp->toChars());
+        result = exp;
+    }
+
+    void visit(FuncExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("FuncExp::semantic(%s)\n", exp->toChars());
+        if (exp->fd->treq) printf("  treq = %s\n", exp->fd->treq->toChars());
+#endif
+        Expression *e = exp;
+
+        sc = sc->push();            // just create new scope
+        sc->flags &= ~SCOPEctfe;    // temporary stop CTFE
+        sc->protection = Prot(PROTpublic);    // Bugzilla 12506
+
+        if (!exp->type || exp->type == Type::tvoid)
+        {
+            /* fd->treq might be incomplete type,
+             * so should not semantic it.
+             * void foo(T)(T delegate(int) dg){}
+             * foo(a=>a); // in IFTI, treq == T delegate(int)
+             */
+            //if (exp->fd->treq)
+            //    exp->fd->treq = exp->fd->treq->semantic(exp->loc, sc);
+
+            exp->genIdent(sc);
+
+            // Set target of return type inference
+            if (exp->fd->treq && !exp->fd->type->nextOf())
+            {
+                TypeFunction *tfv = NULL;
+                if (exp->fd->treq->ty == Tdelegate ||
+                    (exp->fd->treq->ty == Tpointer && exp->fd->treq->nextOf()->ty == Tfunction))
+                    tfv = (TypeFunction *)exp->fd->treq->nextOf();
+                if (tfv)
+                {
+                    TypeFunction *tfl = (TypeFunction *)exp->fd->type;
+                    tfl->next = tfv->nextOf();
+                }
+            }
+
+            //printf("td = %p, treq = %p\n", exp->td, exp->fd->treq);
+            if (exp->td)
+            {
+                assert(exp->td->parameters && exp->td->parameters->dim);
+                exp->td->semantic(sc);
+                exp->type = Type::tvoid; // temporary type
+
+                if (exp->fd->treq)       // defer type determination
+                {
+                    FuncExp *fe;
+                    if (exp->matchType(exp->fd->treq, sc, &fe) > MATCHnomatch)
+                        e = fe;
+                    else
+                        e = new ErrorExp();
+                }
+                goto Ldone;
+            }
+
+            unsigned olderrors = global.errors;
+            exp->fd->semantic(sc);
+            if (olderrors == global.errors)
+            {
+                exp->fd->semantic2(sc);
+                if (olderrors == global.errors)
+                    exp->fd->semantic3(sc);
+            }
+            if (olderrors != global.errors)
+            {
+                if (exp->fd->type && exp->fd->type->ty == Tfunction && !exp->fd->type->nextOf())
+                    ((TypeFunction *)exp->fd->type)->next = Type::terror;
+                e = new ErrorExp();
+                goto Ldone;
+            }
+
+            // Type is a "delegate to" or "pointer to" the function literal
+            if ((exp->fd->isNested() && exp->fd->tok == TOKdelegate) ||
+                (exp->tok == TOKreserved && exp->fd->treq && exp->fd->treq->ty == Tdelegate))
+            {
+                exp->type = new TypeDelegate(exp->fd->type);
+                exp->type = exp->type->semantic(exp->loc, sc);
+
+                exp->fd->tok = TOKdelegate;
+            }
+            else
+            {
+                exp->type = new TypePointer(exp->fd->type);
+                exp->type = exp->type->semantic(exp->loc, sc);
+                //exp->type = exp->fd->type->pointerTo();
+
+                /* A lambda expression deduced to function pointer might become
+                 * to a delegate literal implicitly.
+                 *
+                 *   auto foo(void function() fp) { return 1; }
+                 *   assert(foo({}) == 1);
+                 *
+                 * So, should keep fd->tok == TOKreserve if fd->treq == NULL.
+                 */
+                if (exp->fd->treq && exp->fd->treq->ty == Tpointer)
+                {
+                    // change to non-nested
+                    exp->fd->tok = TOKfunction;
+                    exp->fd->vthis = NULL;
+                }
+            }
+            exp->fd->tookAddressOf++;
+        }
+    Ldone:
+        sc = sc->pop();
+        result = e;
+    }
+
+    // used from CallExp::semantic()
+    Expression *callExpSemantic(FuncExp *exp, Scope *sc, Expressions *arguments)
+    {
+        if ((!exp->type || exp->type == Type::tvoid) && exp->td && arguments && arguments->dim)
+        {
+            for (size_t k = 0; k < arguments->dim; k++)
+            {   Expression *checkarg = (*arguments)[k];
+                if (checkarg->op == TOKerror)
+                    return checkarg;
+            }
+
+            exp->genIdent(sc);
+
+            assert(exp->td->parameters && exp->td->parameters->dim);
+            exp->td->semantic(sc);
+
+            TypeFunction *tfl = (TypeFunction *)exp->fd->type;
+            size_t dim = Parameter::dim(tfl->parameters);
+            if (arguments->dim < dim)
+            {   // Default arguments are always typed, so they don't need inference.
+                Parameter *p = Parameter::getNth(tfl->parameters, arguments->dim);
+                if (p->defaultArg)
+                    dim = arguments->dim;
+            }
+
+            if ((!tfl->varargs && arguments->dim == dim) ||
+                ( tfl->varargs && arguments->dim >= dim))
+            {
+                Objects *tiargs = new Objects();
+                tiargs->reserve(exp->td->parameters->dim);
+
+                for (size_t i = 0; i < exp->td->parameters->dim; i++)
+                {
+                    TemplateParameter *tp = (*exp->td->parameters)[i];
+                    for (size_t u = 0; u < dim; u++)
+                    {   Parameter *p = Parameter::getNth(tfl->parameters, u);
+                        if (p->type->ty == Tident &&
+                            ((TypeIdentifier *)p->type)->ident == tp->ident)
+                        {   Expression *e = (*arguments)[u];
+                            tiargs->push(e->type);
+                            u = dim;    // break inner loop
+                        }
+                    }
+                }
+
+                TemplateInstance *ti = new TemplateInstance(exp->loc, exp->td, tiargs);
+                Expression *se = new ScopeExp(exp->loc, ti);
+                return semantic(se, sc);
+            }
+            exp->error("cannot infer function literal type");
+            return new ErrorExp();
+        }
+        return semantic(exp, sc);
+    }
+
+    void visit(DeclarationExp *e)
+    {
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+
+#if LOGSEMANTIC
+        printf("DeclarationExp::semantic() %s\n", e->toChars());
+#endif
+
+        unsigned olderrors = global.errors;
+
+        /* This is here to support extern(linkage) declaration,
+         * where the extern(linkage) winds up being an AttribDeclaration
+         * wrapper.
+         */
+        Dsymbol *s = e->declaration;
+
+        while (1)
+        {
+            AttribDeclaration *ad = s->isAttribDeclaration();
+            if (ad)
+            {
+                if (ad->decl && ad->decl->dim == 1)
+                {
+                    s = (*ad->decl)[0];
+                    continue;
+                }
+            }
+            break;
+        }
+
+        VarDeclaration *v = s->isVarDeclaration();
+        if (v)
+        {
+            // Do semantic() on initializer first, so:
+            //      int a = a;
+            // will be illegal.
+            e->declaration->semantic(sc);
+            s->parent = sc->parent;
+        }
+
+        //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc);
+        // Insert into both local scope and function scope.
+        // Must be unique in both.
+        if (s->ident)
+        {
+            if (!sc->insert(s))
+            {
+                e->error("declaration %s is already defined", s->toPrettyChars());
+                return setError();
+            }
+            else if (sc->func)
+            {
+                // Bugzilla 11720 - include Dataseg variables
+                if ((s->isFuncDeclaration() ||
+                     s->isAggregateDeclaration() ||
+                     s->isEnumDeclaration() ||
+                     v && v->isDataseg()) &&
+                    !sc->func->localsymtab->insert(s))
+                {
+                    e->error("declaration %s is already defined in another scope in %s",
+                        s->toPrettyChars(), sc->func->toChars());
+                    return setError();
+                }
+                else
+                {
+                    // Disallow shadowing
+                    for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing)
+                    {
+                        Dsymbol *s2;
+                        if (scx->scopesym && scx->scopesym->symtab &&
+                            (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL &&
+                            s != s2)
+                        {
+                            e->error("%s %s is shadowing %s %s", s->kind(), s->ident->toChars(), s2->kind(), s2->toPrettyChars());
+                            return setError();
+                        }
+                    }
+                }
+            }
+        }
+        if (!s->isVarDeclaration())
+        {
+            Scope *sc2 = sc;
+            if (sc2->stc & (STCpure | STCnothrow | STCnogc))
+                sc2 = sc->push();
+            sc2->stc &= ~(STCpure | STCnothrow | STCnogc);
+            e->declaration->semantic(sc2);
+            if (sc2 != sc)
+                sc2->pop();
+            s->parent = sc->parent;
+        }
+        if (global.errors == olderrors)
+        {
+            e->declaration->semantic2(sc);
+            if (global.errors == olderrors)
+            {
+                e->declaration->semantic3(sc);
+            }
+        }
+        // todo: error in declaration should be propagated.
+
+        e->type = Type::tvoid;
+        result = e;
+    }
+
+    void visit(TypeidExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("TypeidExp::semantic() %s\n", exp->toChars());
+#endif
+        Type *ta = isType(exp->obj);
+        Expression *ea = isExpression(exp->obj);
+        Dsymbol *sa = isDsymbol(exp->obj);
+
+        //printf("ta %p ea %p sa %p\n", ta, ea, sa);
+
+        if (ta)
+        {
+            ta->resolve(exp->loc, sc, &ea, &ta, &sa, true);
+        }
+
+        if (ea)
+        {
+            if (Dsymbol *sym = getDsymbol(ea))
+                ea = resolve(exp->loc, sc, sym, false);
+            else
+                ea = semantic(ea, sc);
+            ea = resolveProperties(sc, ea);
+            ta = ea->type;
+            if (ea->op == TOKtype)
+                ea = NULL;
+        }
+
+        if (!ta)
+        {
+            //printf("ta %p ea %p sa %p\n", ta, ea, sa);
+            exp->error("no type for typeid(%s)", ea ? ea->toChars() : (sa ? sa->toChars() : ""));
+            return setError();
+        }
+
+        if (global.params.vcomplex)
+            ta->checkComplexTransition(exp->loc);
+
+        Expression *e;
+        if (ea && ta->toBasetype()->ty == Tclass)
+        {
+            /* Get the dynamic type, which is .classinfo
+            */
+            ea = semantic(ea, sc);
+            e = new TypeidExp(ea->loc, ea);
+            e->type = Type::typeinfoclass->type;
+        }
+        else if (ta->ty == Terror)
+        {
+            e = new ErrorExp();
+        }
+        else
+        {
+            // Handle this in the glue layer
+            e = new TypeidExp(exp->loc, ta);
+            e->type = getTypeInfoType(ta, sc);
+
+            semanticTypeInfo(sc, ta);
+
+            if (ea)
+            {
+                e = new CommaExp(exp->loc, ea, e);       // execute ea
+                e = semantic(e, sc);
+            }
+        }
+        result = e;
+    }
+
+    void visit(TraitsExp *e)
+    {
+        result = semanticTraits(e, sc);
+    }
+
+    void visit(HaltExp *e)
+    {
+#if LOGSEMANTIC
+        printf("HaltExp::semantic()\n");
+#endif
+        e->type = Type::tvoid;
+        result = e;
+    }
+
+    void visit(IsExp *e)
+    {
+        /* is(targ id tok tspec)
+         * is(targ id :  tok2)
+         * is(targ id == tok2)
+         */
+
+        //printf("IsExp::semantic(%s)\n", toChars());
+        if (e->id && !(sc->flags & SCOPEcondition))
+        {
+            e->error("can only declare type aliases within static if conditionals or static asserts");
+            return setError();
+        }
+
+        Type *tded = NULL;
+        Scope *sc2 = sc->copy();    // keep sc->flags
+        sc2->tinst = NULL;
+        sc2->minst = NULL;
+        sc2->flags |= SCOPEfullinst;
+        Type *t = e->targ->trySemantic(e->loc, sc2);
+        sc2->pop();
+        if (!t)
+            goto Lno;                       // errors, so condition is false
+        e->targ = t;
+        if (e->tok2 != TOKreserved)
+        {
+            switch (e->tok2)
+            {
+                case TOKstruct:
+                    if (e->targ->ty != Tstruct)
+                        goto Lno;
+                    if (((TypeStruct *)e->targ)->sym->isUnionDeclaration())
+                        goto Lno;
+                    tded = e->targ;
+                    break;
+
+                case TOKunion:
+                    if (e->targ->ty != Tstruct)
+                        goto Lno;
+                    if (!((TypeStruct *)e->targ)->sym->isUnionDeclaration())
+                        goto Lno;
+                    tded = e->targ;
+                    break;
+
+                case TOKclass:
+                    if (e->targ->ty != Tclass)
+                        goto Lno;
+                    if (((TypeClass *)e->targ)->sym->isInterfaceDeclaration())
+                        goto Lno;
+                    tded = e->targ;
+                    break;
+
+                case TOKinterface:
+                    if (e->targ->ty != Tclass)
+                        goto Lno;
+                    if (!((TypeClass *)e->targ)->sym->isInterfaceDeclaration())
+                        goto Lno;
+                    tded = e->targ;
+                    break;
+                case TOKconst:
+                    if (!e->targ->isConst())
+                        goto Lno;
+                    tded = e->targ;
+                    break;
+
+                case TOKimmutable:
+                    if (!e->targ->isImmutable())
+                        goto Lno;
+                    tded = e->targ;
+                    break;
+
+                case TOKshared:
+                    if (!e->targ->isShared())
+                        goto Lno;
+                    tded = e->targ;
+                    break;
+
+                case TOKwild:
+                    if (!e->targ->isWild())
+                        goto Lno;
+                    tded = e->targ;
+                    break;
+
+                case TOKsuper:
+                    // If class or interface, get the base class and interfaces
+                    if (e->targ->ty != Tclass)
+                        goto Lno;
+                    else
+                    {
+                        ClassDeclaration *cd = ((TypeClass *)e->targ)->sym;
+                        Parameters *args = new Parameters;
+                        args->reserve(cd->baseclasses->dim);
+                        if (cd->_scope && !cd->symtab)
+                            cd->semantic(cd->_scope);
+                        for (size_t i = 0; i < cd->baseclasses->dim; i++)
+                        {
+                            BaseClass *b = (*cd->baseclasses)[i];
+                            args->push(new Parameter(STCin, b->type, NULL, NULL));
+                        }
+                        tded = new TypeTuple(args);
+                    }
+                    break;
+
+                case TOKenum:
+                    if (e->targ->ty != Tenum)
+                        goto Lno;
+                    if (e->id)
+                        tded = ((TypeEnum *)e->targ)->sym->getMemtype(e->loc);
+                    else
+                        tded = e->targ;
+                    if (tded->ty == Terror)
+                        return setError();
+                    break;
+
+                case TOKdelegate:
+                    if (e->targ->ty != Tdelegate)
+                        goto Lno;
+                    tded = ((TypeDelegate *)e->targ)->next;    // the underlying function type
+                    break;
+
+                case TOKfunction:
+                case TOKparameters:
+                    {
+                        if (e->targ->ty != Tfunction)
+                            goto Lno;
+                        tded = e->targ;
+
+                        /* Generate tuple from function parameter types.
+                        */
+                        assert(tded->ty == Tfunction);
+                        Parameters *params = ((TypeFunction *)tded)->parameters;
+                        size_t dim = Parameter::dim(params);
+                        Parameters *args = new Parameters;
+                        args->reserve(dim);
+                        for (size_t i = 0; i < dim; i++)
+                        {
+                            Parameter *arg = Parameter::getNth(params, i);
+                            assert(arg && arg->type);
+                            /* If one of the default arguments was an error,
+                               don't return an invalid tuple
+                               */
+                            if (e->tok2 == TOKparameters && arg->defaultArg &&
+                                arg->defaultArg->op == TOKerror)
+                                return setError();
+                            args->push(new Parameter(arg->storageClass, arg->type,
+                                                     (e->tok2 == TOKparameters) ? arg->ident : NULL,
+                                                     (e->tok2 == TOKparameters) ? arg->defaultArg : NULL));
+                        }
+                        tded = new TypeTuple(args);
+                        break;
+                    }
+                case TOKreturn:
+                    /* Get the 'return type' for the function,
+                     * delegate, or pointer to function.
+                     */
+                    if (e->targ->ty == Tfunction)
+                        tded = ((TypeFunction *)e->targ)->next;
+                    else if (e->targ->ty == Tdelegate)
+                    {
+                        tded = ((TypeDelegate *)e->targ)->next;
+                        tded = ((TypeFunction *)tded)->next;
+                    }
+                    else if (e->targ->ty == Tpointer &&
+                             ((TypePointer *)e->targ)->next->ty == Tfunction)
+                    {
+                        tded = ((TypePointer *)e->targ)->next;
+                        tded = ((TypeFunction *)tded)->next;
+                    }
+                    else
+                        goto Lno;
+                    break;
+
+                case TOKargTypes:
+                    /* Generate a type tuple of the equivalent types used to determine if a
+                     * function argument of this type can be passed in registers.
+                     * The results of this are highly platform dependent, and intended
+                     * primarly for use in implementing va_arg().
+                     */
+                    tded = toArgTypes(e->targ);
+                    if (!tded)
+                        goto Lno;           // not valid for a parameter
+                    break;
+
+                case TOKvector:
+                    if (e->targ->ty != Tvector)
+                        goto Lno;
+                    tded = ((TypeVector *)e->targ)->basetype;
+                    break;
+
+                default:
+                    assert(0);
+            }
+            goto Lyes;
+        }
+        else if (e->tspec && !e->id && !(e->parameters && e->parameters->dim))
+        {
+            /* Evaluate to true if targ matches tspec
+             * is(targ == tspec)
+             * is(targ : tspec)
+             */
+            e->tspec = e->tspec->semantic(e->loc, sc);
+            //printf("targ  = %s, %s\n", e->targ->toChars(), e->targ->deco);
+            //printf("tspec = %s, %s\n", e->tspec->toChars(), e->tspec->deco);
+            if (e->tok == TOKcolon)
+            {
+                if (e->targ->implicitConvTo(e->tspec))
+                    goto Lyes;
+                else
+                    goto Lno;
+            }
+            else /* == */
+            {
+                if (e->targ->equals(e->tspec))
+                    goto Lyes;
+                else
+                    goto Lno;
+            }
+        }
+        else if (e->tspec)
+        {
+            /* Evaluate to true if targ matches tspec.
+             * If true, declare id as an alias for the specialized type.
+             * is(targ == tspec, tpl)
+             * is(targ : tspec, tpl)
+             * is(targ id == tspec)
+             * is(targ id : tspec)
+             * is(targ id == tspec, tpl)
+             * is(targ id : tspec, tpl)
+             */
+
+            Identifier *tid = e->id ? e->id : Identifier::generateId("__isexp_id");
+            e->parameters->insert(0, new TemplateTypeParameter(e->loc, tid, NULL, NULL));
+
+            Objects dedtypes;
+            dedtypes.setDim(e->parameters->dim);
+            dedtypes.zero();
+
+            MATCH m = deduceType(e->targ, sc, e->tspec, e->parameters, &dedtypes);
+            //printf("targ: %s\n", e->targ->toChars());
+            //printf("tspec: %s\n", e->tspec->toChars());
+            if (m <= MATCHnomatch ||
+                (m != MATCHexact && e->tok == TOKequal))
+            {
+                goto Lno;
+            }
+            else
+            {
+                tded = (Type *)dedtypes[0];
+                if (!tded)
+                    tded = e->targ;
+                Objects tiargs;
+                tiargs.setDim(1);
+                tiargs[0] = e->targ;
+
+                /* Declare trailing parameters
+                */
+                for (size_t i = 1; i < e->parameters->dim; i++)
+                {
+                    TemplateParameter *tp = (*e->parameters)[i];
+                    Declaration *s = NULL;
+
+                    m = tp->matchArg(e->loc, sc, &tiargs, i, e->parameters, &dedtypes, &s);
+                    if (m <= MATCHnomatch)
+                        goto Lno;
+                    s->semantic(sc);
+                    if (sc->sds)
+                        s->addMember(sc, sc->sds);
+                    else if (!sc->insert(s))
+                        e->error("declaration %s is already defined", s->toChars());
+
+                    unSpeculative(sc, s);
+                }
+                goto Lyes;
+            }
+        }
+        else if (e->id)
+        {
+            /* Declare id as an alias for type targ. Evaluate to true
+             * is(targ id)
+             */
+            tded = e->targ;
+            goto Lyes;
+        }
+
+    Lyes:
+        if (e->id)
+        {
+            Dsymbol *s;
+            Tuple *tup = isTuple(tded);
+            if (tup)
+                s = new TupleDeclaration(e->loc, e->id, &(tup->objects));
+            else
+                s = new AliasDeclaration(e->loc, e->id, tded);
+            s->semantic(sc);
+            /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
+             * More investigation is needed.
+             */
+            if (!tup && !sc->insert(s))
+                e->error("declaration %s is already defined", s->toChars());
+            if (sc->sds)
+                s->addMember(sc, sc->sds);
+
+            unSpeculative(sc, s);
+        }
+        //printf("Lyes\n");
+        result = new IntegerExp(e->loc, 1, Type::tbool);
+        return;
+
+    Lno:
+        //printf("Lno\n");
+        result = new IntegerExp(e->loc, 0, Type::tbool);
+    }
+
+    void visit(BinAssignExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (exp->e1->checkReadModifyWrite(exp->op, exp->e2))
+            return setError();
+
+        if (exp->e1->op == TOKarraylength)
+        {
+            // arr.length op= e2;
+            e = ArrayLengthExp::rewriteOpAssign(exp);
+            e = semantic(e, sc);
+            result = e;
+            return;
+        }
+        if (exp->e1->op == TOKslice || exp->e1->type->ty == Tarray || exp->e1->type->ty == Tsarray)
+        {
+            // T[] op= ...
+            if (exp->e2->implicitConvTo(exp->e1->type->nextOf()))
+            {
+                // T[] op= T
+                exp->e2 = exp->e2->castTo(sc, exp->e1->type->nextOf());
+            }
+            else if (Expression *ex = typeCombine(exp, sc))
+            {
+                result = ex;
+                return;
+            }
+            exp->type = exp->e1->type;
+            result = arrayOp(exp, sc);
+            return;
+        }
+
+        exp->e1 = semantic(exp->e1, sc);
+        exp->e1 = exp->e1->optimize(WANTvalue);
+        exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
+        exp->type = exp->e1->type;
+        if (exp->checkScalar())
+            return setError();
+
+        int arith = (exp->op == TOKaddass || exp->op == TOKminass || exp->op == TOKmulass ||
+                     exp->op == TOKdivass || exp->op == TOKmodass || exp->op == TOKpowass);
+        int bitwise = (exp->op == TOKandass || exp->op == TOKorass || exp->op == TOKxorass);
+        int shift = (exp->op == TOKshlass || exp->op == TOKshrass || exp->op == TOKushrass);
+
+        if (bitwise && exp->type->toBasetype()->ty == Tbool)
+            exp->e2 = exp->e2->implicitCastTo(sc, exp->type);
+        else if (exp->checkNoBool())
+            return setError();
+
+        if ((exp->op == TOKaddass || exp->op == TOKminass) &&
+            exp->e1->type->toBasetype()->ty == Tpointer &&
+            exp->e2->type->toBasetype()->isintegral())
+        {
+            result = scaleFactor(exp, sc);
+            return;
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        if (arith && exp->checkArithmeticBin())
+            return setError();
+        if ((bitwise || shift) && exp->checkIntegralBin())
+            return setError();
+        if (shift)
+        {
+            if (exp->e2->type->toBasetype()->ty != Tvector)
+                exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
+        }
+
+        if (!Target::isVectorOpSupported(exp->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+
+        if (exp->e1->op == TOKerror || exp->e2->op == TOKerror)
+            return setError();
+
+        e = exp->checkOpAssignTypes(sc);
+        if (e->op == TOKerror)
+        {
+            result = e;
+            return;
+        }
+
+        assert(e->op == TOKassign || e == exp);
+        result = ((BinExp *)e)->reorderSettingAAElem(sc);
+    }
+
+    void visit(CompileExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("CompileExp::semantic('%s')\n", exp->toChars());
+#endif
+        sc = sc->startCTFE();
+        exp->e1 = semantic(exp->e1, sc);
+        exp->e1 = resolveProperties(sc, exp->e1);
+        sc = sc->endCTFE();
+        if (exp->e1->op == TOKerror)
+        {
+            result = exp->e1;
+            return;
+        }
+        if (!exp->e1->type->isString())
+        {
+            exp->error("argument to mixin must be a string type, not %s", exp->e1->type->toChars());
+            return setError();
+        }
+        exp->e1 = exp->e1->ctfeInterpret();
+        StringExp *se = exp->e1->toStringExp();
+        if (!se)
+        {
+            exp->error("argument to mixin must be a string, not (%s)", exp->e1->toChars());
+            return setError();
+        }
+        se = se->toUTF8(sc);
+        unsigned errors = global.errors;
+        Parser p(exp->loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+        p.nextToken();
+        //printf("p.loc.linnum = %d\n", p.loc.linnum);
+        Expression *e = p.parseExpression();
+        if (p.errors)
+        {
+            assert(global.errors != errors);        // should have caught all these cases
+            return setError();
+        }
+        if (p.token.value != TOKeof)
+        {
+            exp->error("incomplete mixin expression (%s)", se->toChars());
+            return setError();
+        }
+        result = semantic(e, sc);
+    }
+
+    void visit(ImportExp *e)
+    {
+        const char *name;
+        StringExp *se;
+
+#if LOGSEMANTIC
+        printf("ImportExp::semantic('%s')\n", e->toChars());
+#endif
+        sc = sc->startCTFE();
+        e->e1 = semantic(e->e1, sc);
+        e->e1 = resolveProperties(sc, e->e1);
+        sc = sc->endCTFE();
+        e->e1 = e->e1->ctfeInterpret();
+        if (e->e1->op != TOKstring)
+        {
+            e->error("file name argument must be a string, not (%s)", e->e1->toChars());
+            goto Lerror;
+        }
+        se = (StringExp *)e->e1;
+        se = se->toUTF8(sc);
+        name = (char *)se->string;
+
+        if (!global.params.fileImppath)
+        {
+            e->error("need -Jpath switch to import text file %s", name);
+            goto Lerror;
+        }
+
+        /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
+         * ('Path Traversal') attacks.
+         * http://cwe.mitre.org/data/definitions/22.html
+         */
+
+        name = FileName::safeSearchPath(global.filePath, name);
+        if (!name)
+        {
+            e->error("file %s cannot be found or not in a path specified with -J", se->toChars());
+            goto Lerror;
+        }
+
+        if (global.params.verbose)
+            fprintf(global.stdmsg, "file      %s\t(%s)\n", (char *)se->string, name);
+        if (global.params.moduleDeps != NULL)
+        {
+            OutBuffer *ob = global.params.moduleDeps;
+            Module* imod = sc->instantiatingModule();
+
+            if (!global.params.moduleDepsFile)
+                ob->writestring("depsFile ");
+            ob->writestring(imod->toPrettyChars());
+            ob->writestring(" (");
+            escapePath(ob, imod->srcfile->toChars());
+            ob->writestring(") : ");
+            if (global.params.moduleDepsFile)
+                ob->writestring("string : ");
+            ob->writestring((char *) se->string);
+            ob->writestring(" (");
+            escapePath(ob, name);
+            ob->writestring(")");
+            ob->writenl();
+        }
+
+        {
+            File f(name);
+            if (f.read())
+            {
+                e->error("cannot read file %s", f.toChars());
+                goto Lerror;
+            }
+            else
+            {
+                f.ref = 1;
+                se = new StringExp(e->loc, f.buffer, f.len);
+            }
+        }
+        result = semantic(se, sc);
+        return;
+
+    Lerror:
+        return setError();
+    }
+
+    void visit(AssertExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("AssertExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (Expression *ex = unaSemantic(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        exp->e1 = resolveProperties(sc, exp->e1);
+        // BUG: see if we can do compile time elimination of the Assert
+        exp->e1 = exp->e1->optimize(WANTvalue);
+        exp->e1 = exp->e1->toBoolean(sc);
+        if (exp->msg)
+        {
+            exp->msg = semantic(exp->msg, sc);
+            exp->msg = resolveProperties(sc, exp->msg);
+            exp->msg = exp->msg->implicitCastTo(sc, Type::tchar->constOf()->arrayOf());
+            exp->msg = exp->msg->optimize(WANTvalue);
+        }
+
+        if (exp->e1->op == TOKerror)
+        {
+            result = exp->e1;
+            return;
+        }
+        if (exp->msg && exp->msg->op == TOKerror)
+        {
+            result = exp->msg;
+            return;
+        }
+
+        bool f1 = checkNonAssignmentArrayOp(exp->e1);
+        bool f2 = exp->msg && checkNonAssignmentArrayOp(exp->msg);
+        if (f1 || f2)
+            return setError();
+
+        if (exp->e1->isBool(false))
+        {
+            FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+            if (fd)
+                fd->hasReturnExp |= 4;
+            sc->callSuper |= CSXhalt;
+            if (sc->fieldinit)
+            {
+                for (size_t i = 0; i < sc->fieldinit_dim; i++)
+                    sc->fieldinit[i] |= CSXhalt;
+            }
+
+            if (!global.params.useAssert)
+            {
+                Expression *e = new HaltExp(exp->loc);
+                e = semantic(e, sc);
+                result = e;
+                return;
+            }
+        }
+        exp->type = Type::tvoid;
+        result = exp;
+    }
+
+    void visit(DotIdExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp->toChars());
+        //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op));
+#endif
+        Expression *e = semanticY(exp, sc, 1);
+        if (e && isDotOpDispatch(e))
+        {
+            unsigned errors = global.startGagging();
+            e = resolvePropertiesX(sc, e);
+            if (global.endGagging(errors))
+                e = NULL;   /* fall down to UFCS */
+            else
+            {
+                result = e;
+                return;
+            }
+        }
+        if (!e)     // if failed to find the property
+        {
+            /* If ident is not a valid property, rewrite:
+             *   e1.ident
+             * as:
+             *   .ident(e1)
+             */
+            e = resolveUFCSProperties(sc, exp);
+        }
+        result = e;
+    }
+
+    void visit(DotTemplateExp *e)
+    {
+        if (Expression *ex = unaSemantic(e, sc))
+        {
+            result = ex;
+            return;
+        }
+        result = e;
+    }
+
+    void visit(DotVarExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("DotVarExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        exp->var = exp->var->toAlias()->isDeclaration();
+
+        exp->e1 = semantic(exp->e1, sc);
+
+        if (TupleDeclaration *tup = exp->var->isTupleDeclaration())
+        {
+            /* Replace:
+             *  e1.tuple(a, b, c)
+             * with:
+             *  tuple(e1.a, e1.b, e1.c)
+             */
+            Expression *e0 = NULL;
+            Expression *ev = sc->func ? extractSideEffect(sc, "__tup", &e0, exp->e1) : exp->e1;
+
+            Expressions *exps = new Expressions;
+            exps->reserve(tup->objects->dim);
+            for (size_t i = 0; i < tup->objects->dim; i++)
+            {
+                RootObject *o = (*tup->objects)[i];
+                Expression *e;
+                if (o->dyncast() == DYNCAST_EXPRESSION)
+                {
+                    e = (Expression *)o;
+                    if (e->op == TOKdsymbol)
+                    {
+                        Dsymbol *s = ((DsymbolExp *)e)->s;
+                        e = new DotVarExp(exp->loc, ev, s->isDeclaration());
+                    }
+                }
+                else if (o->dyncast() == DYNCAST_DSYMBOL)
+                {
+                    e = new DsymbolExp(exp->loc, (Dsymbol *)o);
+                }
+                else if (o->dyncast() == DYNCAST_TYPE)
+                {
+                    e = new TypeExp(exp->loc, (Type *)o);
+                }
+                else
+                {
+                    exp->error("%s is not an expression", o->toChars());
+                    return setError();
+                }
+                exps->push(e);
+            }
+
+            Expression *e = new TupleExp(exp->loc, e0, exps);
+            e = semantic(e, sc);
+            result = e;
+            return;
+        }
+
+        exp->e1 = exp->e1->addDtorHook(sc);
+
+        Type *t1 = exp->e1->type;
+
+        if (FuncDeclaration *fd = exp->var->isFuncDeclaration())
+        {
+            // for functions, do checks after overload resolution
+            if (!fd->functionSemantic())
+                return setError();
+
+            /* Bugzilla 13843: If fd obviously has no overloads, we should
+             * normalize AST, and it will give a chance to wrap fd with FuncExp.
+             */
+            if (fd->isNested() || fd->isFuncLiteralDeclaration())
+            {
+                // (e1, fd)
+                Expression *e = resolve(exp->loc, sc, fd, false);
+                result = Expression::combine(exp->e1, e);
+                return;
+            }
+
+            exp->type = fd->type;
+            assert(exp->type);
+        }
+        else if (OverDeclaration *od = exp->var->isOverDeclaration())
+        {
+            exp->type = Type::tvoid; // ambiguous type?
+        }
+        else
+        {
+            exp->type = exp->var->type;
+            if (!exp->type && global.errors)
+            {
+                // var is goofed up, just return 0
+                return setError();
+            }
+            assert(exp->type);
+
+            if (t1->ty == Tpointer)
+                t1 = t1->nextOf();
+
+            exp->type = exp->type->addMod(t1->mod);
+
+            Dsymbol *vparent = exp->var->toParent();
+            AggregateDeclaration *ad = vparent ? vparent->isAggregateDeclaration() : NULL;
+
+            if (Expression *e1x = getRightThis(exp->loc, sc, ad, exp->e1, exp->var, 1))
+                exp->e1 = e1x;
+            else
+            {
+                /* Later checkRightThis will report correct error for invalid field variable access.
+                */
+                Expression *e = new VarExp(exp->loc, exp->var);
+                e = semantic(e, sc);
+                result = e;
+                return;
+            }
+            checkAccess(exp->loc, sc, exp->e1, exp->var);
+
+            VarDeclaration *v = exp->var->isVarDeclaration();
+            if (v && (v->isDataseg() || (v->storage_class & STCmanifest)))
+            {
+                Expression *e = expandVar(WANTvalue, v);
+                if (e)
+                {
+                    result = e;
+                    return;
+                }
+            }
+
+            if (v && v->isDataseg())     // fix bugzilla 8238
+            {
+                // (e1, v)
+                checkAccess(exp->loc, sc, exp->e1, v);
+                Expression *e = new VarExp(exp->loc, v);
+                e = new CommaExp(exp->loc, exp->e1, e);
+                e = semantic(e, sc);
+                result = e;
+                return;
+            }
+        }
+
+        //printf("-DotVarExp::semantic('%s')\n", exp->toChars());
+        result = exp;
+    }
+
+    void visit(DotTemplateInstanceExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("DotTemplateInstanceExp::semantic('%s')\n", exp->toChars());
+#endif
+
+        // Indicate we need to resolve by UFCS.
+        Expression *e = semanticY(exp, sc, 1);
+        if (!e)
+            e = resolveUFCSProperties(sc, exp);
+        result = e;
+    }
+
+    void visit(DelegateExp *e)
+    {
+#if LOGSEMANTIC
+        printf("DelegateExp::semantic('%s')\n", e->toChars());
+#endif
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+
+        e->e1 = semantic(e->e1, sc);
+        e->type = new TypeDelegate(e->func->type);
+        e->type = e->type->semantic(e->loc, sc);
+        FuncDeclaration *f = e->func->toAliasFunc();
+        AggregateDeclaration *ad = f->toParent()->isAggregateDeclaration();
+        if (f->needThis())
+            e->e1 = getRightThis(e->loc, sc, ad, e->e1, f);
+        if (ad && ad->isClassDeclaration() && ad->type != e->e1->type)
+        {
+            // A downcast is required for interfaces, see Bugzilla 3706
+            e->e1 = new CastExp(e->loc, e->e1, ad->type);
+            e->e1 = semantic(e->e1, sc);
+        }
+        result = e;
+    }
+
+    void visit(DotTypeExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("DotTypeExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (Expression *ex = unaSemantic(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        result = exp;
+    }
+
+    void visit(CallExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("CallExp::semantic() %s\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;            // semantic() already run
+            return;
+        }
+
+        Type *t1;
+        Objects *tiargs = NULL;     // initial list of template arguments
+        Expression *ethis = NULL;
+        Type *tthis = NULL;
+        Expression *e1org = exp->e1;
+
+        if (exp->e1->op == TOKcomma)
+        {
+            /* Rewrite (a,b)(args) as (a,(b(args)))
+            */
+            CommaExp *ce = (CommaExp *)exp->e1;
+            exp->e1 = ce->e2;
+            exp->e1->type = ce->type;
+            ce->e2 = exp;
+            ce->type = NULL;
+            result = semantic(ce, sc);
+            return;
+        }
+
+        if (exp->e1->op == TOKdelegate)
+        {
+            DelegateExp *de = (DelegateExp *)exp->e1;
+            exp->e1 = new DotVarExp(de->loc, de->e1, de->func, de->hasOverloads);
+            result = semantic(exp, sc);
+            return;
+        }
+
+        if (exp->e1->op == TOKfunction)
+        {
+            if (arrayExpressionSemantic(exp->arguments, sc) ||
+                preFunctionParameters(exp->loc, sc, exp->arguments))
+            {
+                return setError();
+            }
+
+            // Run e1 semantic even if arguments have any errors
+            FuncExp *fe = (FuncExp *)exp->e1;
+            exp->e1 = callExpSemantic(fe, sc, exp->arguments);
+            if (exp->e1->op == TOKerror)
+            {
+                result = exp->e1;
+                return;
+            }
+        }
+
+        if (Expression *ex = resolveUFCS(sc, exp))
+        {
+            result = ex;
+            return;
+        }
+
+        /* This recognizes:
+         *  foo!(tiargs)(funcargs)
+         */
+        if (exp->e1->op == TOKscope)
+        {
+            ScopeExp *se = (ScopeExp *)exp->e1;
+            TemplateInstance *ti = se->sds->isTemplateInstance();
+            if (ti)
+            {
+                /* Attempt to instantiate ti. If that works, go with it.
+                 * If not, go with partial explicit specialization.
+                 */
+                WithScopeSymbol *withsym;
+                if (!ti->findTempDecl(sc, &withsym) ||
+                    !ti->semanticTiargs(sc))
+                {
+                    return setError();
+                }
+                if (withsym && withsym->withstate->wthis)
+                {
+                    exp->e1 = new VarExp(exp->e1->loc, withsym->withstate->wthis);
+                    exp->e1 = new DotTemplateInstanceExp(exp->e1->loc, exp->e1, ti);
+                    goto Ldotti;
+                }
+                if (ti->needsTypeInference(sc, 1))
+                {
+                    /* Go with partial explicit specialization
+                    */
+                    tiargs = ti->tiargs;
+                    assert(ti->tempdecl);
+                    if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration())
+                        exp->e1 = new TemplateExp(exp->loc, td);
+                    else if (OverDeclaration *od = ti->tempdecl->isOverDeclaration())
+                        exp->e1 = new VarExp(exp->loc, od);
+                    else
+                        exp->e1 = new OverExp(exp->loc, ti->tempdecl->isOverloadSet());
+                }
+                else
+                {
+                    Expression *e1x = semantic(exp->e1, sc);
+                    if (e1x->op == TOKerror)
+                    {
+                        result = e1x;
+                        return;
+                    }
+                    exp->e1 = e1x;
+                }
+            }
+        }
+
+        /* This recognizes:
+         *  expr.foo!(tiargs)(funcargs)
+         */
+    Ldotti:
+        if (exp->e1->op == TOKdotti && !exp->e1->type)
+        {
+            DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)exp->e1;
+            TemplateInstance *ti = se->ti;
+            {
+                /* Attempt to instantiate ti. If that works, go with it.
+                 * If not, go with partial explicit specialization.
+                 */
+                if (!se->findTempDecl(sc) ||
+                    !ti->semanticTiargs(sc))
+                {
+                    return setError();
+                }
+                if (ti->needsTypeInference(sc, 1))
+                {
+                    /* Go with partial explicit specialization
+                    */
+                    tiargs = ti->tiargs;
+                    assert(ti->tempdecl);
+                    if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration())
+                        exp->e1 = new DotTemplateExp(exp->loc, se->e1, td);
+                    else if (OverDeclaration *od = ti->tempdecl->isOverDeclaration())
+                    {
+                        exp->e1 = new DotVarExp(exp->loc, se->e1, od, true);
+                    }
+                    else
+                        exp->e1 = new DotExp(exp->loc, se->e1, new OverExp(exp->loc, ti->tempdecl->isOverloadSet()));
+                }
+                else
+                {
+                    Expression *e1x = semantic(exp->e1, sc);
+                    if (e1x->op == TOKerror)
+                    {
+                        result =e1x;
+                        return;
+                    }
+                    exp->e1 = e1x;
+                }
+            }
+        }
+
+    Lagain:
+        //printf("Lagain: %s\n", exp->toChars());
+        exp->f = NULL;
+        if (exp->e1->op == TOKthis || exp->e1->op == TOKsuper)
+        {
+            // semantic() run later for these
+        }
+        else
+        {
+            if (exp->e1->op == TOKdotid)
+            {
+                DotIdExp *die = (DotIdExp *)exp->e1;
+                exp->e1 = semantic(die, sc);
+                /* Look for e1 having been rewritten to expr.opDispatch!(string)
+                 * We handle such earlier, so go back.
+                 * Note that in the rewrite, we carefully did not run semantic() on e1
+                 */
+                if (exp->e1->op == TOKdotti && !exp->e1->type)
+                {
+                    goto Ldotti;
+                }
+            }
+            else
+            {
+                static int nest;
+                if (++nest > 500)
+                {
+                    exp->error("recursive evaluation of %s", exp->toChars());
+                    --nest;
+                    return setError();
+                }
+                Expression *ex = unaSemantic(exp, sc);
+                --nest;
+                if (ex)
+                {
+                    result = ex;
+                    return;
+                }
+            }
+
+            /* Look for e1 being a lazy parameter
+            */
+            if (exp->e1->op == TOKvar)
+            {
+                VarExp *ve = (VarExp *)exp->e1;
+                if (ve->var->storage_class & STClazy)
+                {
+                    // lazy paramaters can be called without violating purity and safety
+                    Type *tw = ve->var->type;
+                    Type *tc = ve->var->type->substWildTo(MODconst);
+                    TypeFunction *tf = new TypeFunction(NULL, tc, 0, LINKd, STCsafe | STCpure);
+                    (tf = (TypeFunction *)tf->semantic(exp->loc, sc))->next = tw;    // hack for bug7757
+                    TypeDelegate *t = new TypeDelegate(tf);
+                    ve->type = t->semantic(exp->loc, sc);
+                }
+                VarDeclaration *v = ve->var->isVarDeclaration();
+                if (v && ve->checkPurity(sc, v))
+                    return setError();
+            }
+
+            if (exp->e1->op == TOKscope)
+            {
+                // Perhaps this should be moved to ScopeExp::semantic()
+                ScopeExp *se = (ScopeExp *)exp->e1;
+                exp->e1 = resolve(exp->loc, sc, se->sds, false);
+            }
+            else if (exp->e1->op == TOKsymoff && ((SymOffExp *)exp->e1)->hasOverloads)
+            {
+                SymOffExp *se = (SymOffExp *)exp->e1;
+                exp->e1 = new VarExp(se->loc, se->var, true);
+                exp->e1 = semantic(exp->e1, sc);
+            }
+            else if (exp->e1->op == TOKdot)
+            {
+                DotExp *de = (DotExp *) exp->e1;
+
+                if (de->e2->op == TOKoverloadset)
+                {
+                    ethis = de->e1;
+                    tthis = de->e1->type;
+                    exp->e1 = de->e2;
+                }
+
+                if (de->e2->op == TOKscope)
+                {
+                    // This should *really* be moved to ScopeExp::semantic()
+                    ScopeExp *se = (ScopeExp *)de->e2;
+                    de->e2 = resolve(exp->loc, sc, se->sds, false);
+                }
+
+                if (de->e2->op == TOKtemplate)
+                {
+                    TemplateExp *te = (TemplateExp *) de->e2;
+                    exp->e1 = new DotTemplateExp(exp->loc,de->e1,te->td);
+                }
+            }
+            else if (exp->e1->op == TOKstar && exp->e1->type->ty == Tfunction)
+            {
+                // Rewrite (*fp)(arguments) to fp(arguments)
+                exp->e1 = ((PtrExp *)exp->e1)->e1;
+            }
+        }
+
+        t1 = exp->e1->type ? exp->e1->type->toBasetype() : NULL;
+
+        if (exp->e1->op == TOKerror)
+        {
+            result = exp->e1;
+            return;
+        }
+        if (arrayExpressionSemantic(exp->arguments, sc) ||
+            preFunctionParameters(exp->loc, sc, exp->arguments))
+        {
+            return setError();
+        }
+
+        // Check for call operator overload
+        if (t1)
+        {
+            if (t1->ty == Tstruct)
+            {
+                StructDeclaration *sd = ((TypeStruct *)t1)->sym;
+                sd->size(exp->loc);      // Resolve forward references to construct object
+                if (sd->sizeok != SIZEOKdone)
+                    return setError();
+                if (!sd->ctor)
+                    sd->ctor = sd->searchCtor();
+
+                // First look for constructor
+                if (exp->e1->op == TOKtype && sd->ctor)
+                {
+                    if (!sd->noDefaultCtor && !(exp->arguments && exp->arguments->dim))
+                        goto Lx;
+
+                    StructLiteralExp *sle = new StructLiteralExp(exp->loc, sd, NULL, exp->e1->type);
+                    if (!sd->fill(exp->loc, sle->elements, true))
+                        return setError();
+                    if (checkFrameAccess(exp->loc, sc, sd, sle->elements->dim))
+                        return setError();
+                    // Bugzilla 14556: Set concrete type to avoid further redundant semantic().
+                    sle->type = exp->e1->type;
+
+                    /* Constructor takes a mutable object, so don't use
+                     * the immutable initializer symbol.
+                     */
+                    sle->useStaticInit = false;
+
+                    Expression *e = sle;
+                    if (CtorDeclaration *cf = sd->ctor->isCtorDeclaration())
+                    {
+                        e = new DotVarExp(exp->loc, e, cf, true);
+                    }
+                    else if (TemplateDeclaration *td = sd->ctor->isTemplateDeclaration())
+                    {
+                        e = new DotTemplateExp(exp->loc, e, td);
+                    }
+                    else if (OverloadSet *os = sd->ctor->isOverloadSet())
+                    {
+                        e = new DotExp(exp->loc, e, new OverExp(exp->loc, os));
+                    }
+                    else
+                        assert(0);
+                    e = new CallExp(exp->loc, e, exp->arguments);
+                    result = semantic(e, sc);
+                    return;
+                }
+                // No constructor, look for overload of opCall
+                if (search_function(sd, Id::call))
+                    goto L1;        // overload of opCall, therefore it's a call
+
+                if (exp->e1->op != TOKtype)
+                {
+                    if (sd->aliasthis && exp->e1->type != exp->att1)
+                    {
+                        if (!exp->att1 && exp->e1->type->checkAliasThisRec())
+                            exp->att1 = exp->e1->type;
+                        exp->e1 = resolveAliasThis(sc, exp->e1);
+                        goto Lagain;
+                    }
+                    exp->error("%s %s does not overload ()", sd->kind(), sd->toChars());
+                    return setError();
+                }
+
+                /* It's a struct literal
+                */
+            Lx:
+                Expression *e = new StructLiteralExp(exp->loc, sd, exp->arguments, exp->e1->type);
+                result = semantic(e, sc);
+                return;
+            }
+            else if (t1->ty == Tclass)
+            {
+            L1:
+                // Rewrite as e1.call(arguments)
+                Expression *e = new DotIdExp(exp->loc, exp->e1, Id::call);
+                e = new CallExp(exp->loc, e, exp->arguments);
+                result = semantic(e, sc);
+                return;
+            }
+            else if (exp->e1->op == TOKtype && t1->isscalar())
+            {
+                Expression *e;
+                if (!exp->arguments || exp->arguments->dim == 0)
+                {
+                    e = t1->defaultInitLiteral(exp->loc);
+                }
+                else if (exp->arguments->dim == 1)
+                {
+                    e = (*exp->arguments)[0];
+                    e = e->implicitCastTo(sc, t1);
+                    e = new CastExp(exp->loc, e, t1);
+                }
+                else
+                {
+                    exp->error("more than one argument for construction of %s", t1->toChars());
+                    e = new ErrorExp();
+                }
+                result = semantic(e, sc);
+                return;
+            }
+        }
+
+        if (exp->e1->op == TOKdotvar && t1->ty == Tfunction ||
+            exp->e1->op == TOKdottd)
+        {
+            UnaExp *ue = (UnaExp *)(exp->e1);
+
+            Expression *ue1 = ue->e1;
+            Expression *ue1old = ue1;   // need for 'right this' check
+            VarDeclaration *v;
+            if (ue1->op == TOKvar &&
+                (v = ((VarExp *)ue1)->var->isVarDeclaration()) != NULL &&
+                v->needThis())
+            {
+                ue->e1 = new TypeExp(ue1->loc, ue1->type);
+                ue1 = NULL;
+            }
+
+            DotVarExp *dve;
+            DotTemplateExp *dte;
+            Dsymbol *s;
+            if (exp->e1->op == TOKdotvar)
+            {
+                dve = (DotVarExp *)(exp->e1);
+                dte = NULL;
+                s = dve->var;
+                tiargs = NULL;
+            }
+            else
+            {
+                dve = NULL;
+                dte = (DotTemplateExp *)(exp->e1);
+                s = dte->td;
+            }
+
+            // Do overload resolution
+            exp->f = resolveFuncCall(exp->loc, sc, s, tiargs, ue1 ? ue1->type : NULL, exp->arguments);
+            if (!exp->f || exp->f->errors || exp->f->type->ty == Terror)
+                return setError();
+            if (exp->f->interfaceVirtual)
+            {
+                /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
+                */
+                BaseClass *b = exp->f->interfaceVirtual;
+                ClassDeclaration *ad2 = b->sym;
+                ue->e1 = ue->e1->castTo(sc, ad2->type->addMod(ue->e1->type->mod));
+                ue->e1 = semantic(ue->e1, sc);
+                ue1 = ue->e1;
+                int vi = exp->f->findVtblIndex((Dsymbols*)&ad2->vtbl, (int)ad2->vtbl.dim);
+                assert(vi >= 0);
+                exp->f = ad2->vtbl[vi]->isFuncDeclaration();
+                assert(exp->f);
+            }
+            if (exp->f->needThis())
+            {
+                AggregateDeclaration *ad = exp->f->toParent2()->isAggregateDeclaration();
+                ue->e1 = getRightThis(exp->loc, sc, ad, ue->e1, exp->f);
+                if (ue->e1->op == TOKerror)
+                {
+                    result = ue->e1;
+                    return;
+                }
+                ethis = ue->e1;
+                tthis = ue->e1->type;
+                if (!(exp->f->type->ty == Tfunction && ((TypeFunction *)exp->f->type)->isscope))
+                {
+                    if (global.params.vsafe && checkParamArgumentEscape(sc, exp->f, Id::This, ethis, false))
+                        return setError();
+                }
+            }
+
+            /* Cannot call public functions from inside invariant
+             * (because then the invariant would have infinite recursion)
+             */
+            if (sc->func && sc->func->isInvariantDeclaration() &&
+                ue->e1->op == TOKthis &&
+                exp->f->addPostInvariant()
+               )
+            {
+                exp->error("cannot call public/export function %s from invariant", exp->f->toChars());
+                return setError();
+            }
+
+            exp->checkDeprecated(sc, exp->f);
+            exp->checkPurity(sc, exp->f);
+            exp->checkSafety(sc, exp->f);
+            exp->checkNogc(sc, exp->f);
+            checkAccess(exp->loc, sc, ue->e1, exp->f);
+            if (!exp->f->needThis())
+            {
+                VarExp *ve = new VarExp(exp->loc, exp->f, false);
+                if ((ue->e1)->op == TOKtype) // just a FQN
+                    exp->e1 = ve;
+                else // things like (new Foo).bar()
+                    exp->e1 = new CommaExp(exp->loc, ue->e1, ve);
+                exp->e1->type = exp->f->type;
+            }
+            else
+            {
+                if (ue1old->checkRightThis(sc))
+                    return setError();
+                if (exp->e1->op == TOKdotvar)
+                {
+                    dve->var = exp->f;
+                    exp->e1->type = exp->f->type;
+                }
+                else
+                {
+                    exp->e1 = new DotVarExp(exp->loc, dte->e1, exp->f, false);
+                    exp->e1 = semantic(exp->e1, sc);
+                    if (exp->e1->op == TOKerror)
+                        return setError();
+                    ue = (UnaExp *)exp->e1;
+                }
+
+                // See if we need to adjust the 'this' pointer
+                AggregateDeclaration *ad = exp->f->isThis();
+                ClassDeclaration *cd = ue->e1->type->isClassHandle();
+                if (ad && cd && ad->isClassDeclaration())
+                {
+                    if (ue->e1->op == TOKdottype)
+                    {
+                        ue->e1 = ((DotTypeExp *)ue->e1)->e1;
+                        exp->directcall = true;
+                    }
+                    else if (ue->e1->op == TOKsuper)
+                        exp->directcall = true;
+                    else if ((cd->storage_class & STCfinal) != 0)   // Bugzilla 14211
+                        exp->directcall = true;
+
+                    if (ad != cd)
+                    {
+                        ue->e1 = ue->e1->castTo(sc, ad->type->addMod(ue->e1->type->mod));
+                        ue->e1 = semantic(ue->e1, sc);
+                    }
+                }
+            }
+            t1 = exp->e1->type;
+        }
+        else if (exp->e1->op == TOKsuper)
+        {
+            // Base class constructor call
+            AggregateDeclaration *ad = sc->func ? sc->func->isThis() : NULL;
+            ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL;
+            if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration())
+            {
+                exp->error("super class constructor call must be in a constructor");
+                return setError();
+            }
+            if (!cd->baseClass->ctor)
+            {
+                exp->error("no super class constructor for %s", cd->baseClass->toChars());
+                return setError();
+            }
+
+            if (!sc->intypeof && !(sc->callSuper & CSXhalt))
+            {
+                if (sc->noctor || sc->callSuper & CSXlabel)
+                    exp->error("constructor calls not allowed in loops or after labels");
+                if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
+                    exp->error("multiple constructor calls");
+                if ((sc->callSuper & CSXreturn) && !(sc->callSuper & CSXany_ctor))
+                    exp->error("an earlier return statement skips constructor");
+                sc->callSuper |= CSXany_ctor | CSXsuper_ctor;
+            }
+
+            tthis = cd->type->addMod(sc->func->type->mod);
+            if (OverloadSet *os = cd->baseClass->ctor->isOverloadSet())
+                exp->f = resolveOverloadSet(exp->loc, sc, os, NULL, tthis, exp->arguments);
+            else
+                exp->f = resolveFuncCall(exp->loc, sc, cd->baseClass->ctor, NULL, tthis, exp->arguments, 0);
+            if (!exp->f || exp->f->errors)
+                return setError();
+            exp->checkDeprecated(sc, exp->f);
+            exp->checkPurity(sc, exp->f);
+            exp->checkSafety(sc, exp->f);
+            exp->checkNogc(sc, exp->f);
+            checkAccess(exp->loc, sc, NULL, exp->f);
+
+            exp->e1 = new DotVarExp(exp->e1->loc, exp->e1, exp->f, false);
+            exp->e1 = semantic(exp->e1, sc);
+            t1 = exp->e1->type;
+        }
+        else if (exp->e1->op == TOKthis)
+        {
+            // same class constructor call
+            AggregateDeclaration *ad = sc->func ? sc->func->isThis() : NULL;
+            if (!ad || !sc->func->isCtorDeclaration())
+            {
+                exp->error("constructor call must be in a constructor");
+                return setError();
+            }
+
+            if (!sc->intypeof && !(sc->callSuper & CSXhalt))
+            {
+                if (sc->noctor || sc->callSuper & CSXlabel)
+                    exp->error("constructor calls not allowed in loops or after labels");
+                if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
+                    exp->error("multiple constructor calls");
+                if ((sc->callSuper & CSXreturn) && !(sc->callSuper & CSXany_ctor))
+                    exp->error("an earlier return statement skips constructor");
+                sc->callSuper |= CSXany_ctor | CSXthis_ctor;
+            }
+
+            tthis = ad->type->addMod(sc->func->type->mod);
+            if (OverloadSet *os = ad->ctor->isOverloadSet())
+                exp->f = resolveOverloadSet(exp->loc, sc, os, NULL, tthis, exp->arguments);
+            else
+                exp->f = resolveFuncCall(exp->loc, sc, ad->ctor, NULL, tthis, exp->arguments, 0);
+            if (!exp->f || exp->f->errors)
+                return setError();
+            exp->checkDeprecated(sc, exp->f);
+            exp->checkPurity(sc, exp->f);
+            exp->checkSafety(sc, exp->f);
+            exp->checkNogc(sc, exp->f);
+            //checkAccess(exp->loc, sc, NULL, exp->f);    // necessary?
+
+            exp->e1 = new DotVarExp(exp->e1->loc, exp->e1, exp->f, false);
+            exp->e1 = semantic(exp->e1, sc);
+            t1 = exp->e1->type;
+
+            // BUG: this should really be done by checking the static
+            // call graph
+            if (exp->f == sc->func)
+            {
+                exp->error("cyclic constructor call");
+                return setError();
+            }
+        }
+        else if (exp->e1->op == TOKoverloadset)
+        {
+            OverloadSet *os = ((OverExp *)exp->e1)->vars;
+            exp->f = resolveOverloadSet(exp->loc, sc, os, tiargs, tthis, exp->arguments);
+            if (!exp->f)
+                return setError();
+            if (ethis)
+                exp->e1 = new DotVarExp(exp->loc, ethis, exp->f, false);
+            else
+                exp->e1 = new VarExp(exp->loc, exp->f, false);
+            goto Lagain;
+        }
+        else if (!t1)
+        {
+            exp->error("function expected before (), not '%s'", exp->e1->toChars());
+            return setError();
+        }
+        else if (t1->ty == Terror)
+        {
+            return setError();
+        }
+        else if (t1->ty != Tfunction)
+        {
+            TypeFunction *tf;
+            const char *p;
+            Dsymbol *s;
+            exp->f = NULL;
+            if (exp->e1->op == TOKfunction)
+            {
+                // function literal that direct called is always inferred.
+                assert(((FuncExp *)exp->e1)->fd);
+                exp->f = ((FuncExp *)exp->e1)->fd;
+                tf = (TypeFunction *)exp->f->type;
+                p = "function literal";
+            }
+            else if (t1->ty == Tdelegate)
+            {
+                TypeDelegate *td = (TypeDelegate *)t1;
+                assert(td->next->ty == Tfunction);
+                tf = (TypeFunction *)(td->next);
+                p = "delegate";
+            }
+            else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction)
+            {
+                tf = (TypeFunction *)(((TypePointer *)t1)->next);
+                p = "function pointer";
+            }
+            else if (exp->e1->op == TOKdotvar &&
+                     ((DotVarExp *)exp->e1)->var->isOverDeclaration())
+            {
+                DotVarExp *dve = (DotVarExp *)exp->e1;
+                exp->f = resolveFuncCall(exp->loc, sc, dve->var, tiargs, dve->e1->type, exp->arguments, 2);
+                if (!exp->f)
+                    return setError();
+                if (exp->f->needThis())
+                {
+                    dve->var = exp->f;
+                    dve->type = exp->f->type;
+                    dve->hasOverloads = false;
+                    goto Lagain;
+                }
+                exp->e1 = new VarExp(dve->loc, exp->f, false);
+                Expression *e = new CommaExp(exp->loc, dve->e1, exp);
+                result = semantic(e, sc);
+                return;
+            }
+            else if (exp->e1->op == TOKvar &&
+                     ((VarExp *)exp->e1)->var->isOverDeclaration())
+            {
+                s = ((VarExp *)exp->e1)->var;
+                goto L2;
+            }
+            else if (exp->e1->op == TOKtemplate)
+            {
+                s = ((TemplateExp *)exp->e1)->td;
+            L2:
+                exp->f = resolveFuncCall(exp->loc, sc, s, tiargs, NULL, exp->arguments);
+                if (!exp->f || exp->f->errors)
+                    return setError();
+                if (exp->f->needThis())
+                {
+                    if (hasThis(sc))
+                    {
+                        // Supply an implicit 'this', as in
+                        //    this.ident
+                        Expression *ex = new ThisExp(exp->loc);
+                        ex = semantic(ex, sc);
+                        exp->e1 = new DotVarExp(exp->loc, ex, exp->f, false);
+                        goto Lagain;
+                    }
+                    else if (isNeedThisScope(sc, exp->f))
+                    {
+                        exp->error("need 'this' for '%s' of type '%s'", exp->f->toChars(), exp->f->type->toChars());
+                        return setError();
+                    }
+                }
+                exp->e1 = new VarExp(exp->e1->loc, exp->f, false);
+                goto Lagain;
+            }
+            else
+            {
+                exp->error("function expected before (), not %s of type %s", exp->e1->toChars(), exp->e1->type->toChars());
+                return setError();
+            }
+
+            if (!tf->callMatch(NULL, exp->arguments))
+            {
+                OutBuffer buf;
+
+                buf.writeByte('(');
+                argExpTypesToCBuffer(&buf, exp->arguments);
+                buf.writeByte(')');
+                if (tthis)
+                    tthis->modToBuffer(&buf);
+
+                //printf("tf = %s, args = %s\n", tf->deco, (*exp->arguments)[0]->type->deco);
+                ::error(exp->loc, "%s %s %s is not callable using argument types %s",
+                        p, exp->e1->toChars(), parametersTypeToChars(tf->parameters, tf->varargs),
+                        buf.peekString());
+
+                return setError();
+            }
+
+            // Purity and safety check should run after testing arguments matching
+            if (exp->f)
+            {
+                exp->checkPurity(sc, exp->f);
+                exp->checkSafety(sc, exp->f);
+                exp->checkNogc(sc, exp->f);
+                if (exp->f->checkNestedReference(sc, exp->loc))
+                    return setError();
+            }
+            else if (sc->func && sc->intypeof != 1 && !(sc->flags & SCOPEctfe))
+            {
+                bool err = false;
+                if (!tf->purity && !(sc->flags & SCOPEdebug) && sc->func->setImpure())
+                {
+                    exp->error("pure %s '%s' cannot call impure %s '%s'",
+                          sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
+                    err = true;
+                }
+                if (!tf->isnogc && sc->func->setGC())
+                {
+                    exp->error("@nogc %s '%s' cannot call non-@nogc %s '%s'",
+                          sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
+                    err = true;
+                }
+                if (tf->trust <= TRUSTsystem && sc->func->setUnsafe())
+                {
+                    exp->error("@safe %s '%s' cannot call @system %s '%s'",
+                          sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
+                    err = true;
+                }
+                if (err)
+                    return setError();
+            }
+
+            if (t1->ty == Tpointer)
+            {
+                Expression *e = new PtrExp(exp->loc, exp->e1);
+                e->type = tf;
+                exp->e1 = e;
+            }
+            t1 = tf;
+        }
+        else if (exp->e1->op == TOKvar)
+        {
+            // Do overload resolution
+            VarExp *ve = (VarExp *)exp->e1;
+
+            exp->f = ve->var->isFuncDeclaration();
+            assert(exp->f);
+            tiargs = NULL;
+
+            if (ve->hasOverloads)
+                exp->f = resolveFuncCall(exp->loc, sc, exp->f, tiargs, NULL, exp->arguments, 2);
+            else
+            {
+                exp->f = exp->f->toAliasFunc();
+                TypeFunction *tf = (TypeFunction *)exp->f->type;
+                if (!tf->callMatch(NULL, exp->arguments))
+                {
+                    OutBuffer buf;
+
+                    buf.writeByte('(');
+                    argExpTypesToCBuffer(&buf, exp->arguments);
+                    buf.writeByte(')');
+
+                    //printf("tf = %s, args = %s\n", tf->deco, (*exp->arguments)[0]->type->deco);
+                    ::error(exp->loc, "%s %s is not callable using argument types %s",
+                            exp->e1->toChars(), parametersTypeToChars(tf->parameters, tf->varargs),
+                            buf.peekString());
+
+                    exp->f = NULL;
+                }
+            }
+            if (!exp->f || exp->f->errors)
+                return setError();
+
+            if (exp->f->needThis())
+            {
+                // Change the ancestor lambdas to delegate before hasThis(sc) call.
+                if (exp->f->checkNestedReference(sc, exp->loc))
+                    return setError();
+
+                if (hasThis(sc))
+                {
+                    // Supply an implicit 'this', as in
+                    //    this.ident
+
+                    Expression *ex = new ThisExp(exp->loc);
+                    ex = semantic(ex, sc);
+                    exp->e1 = new DotVarExp(exp->loc, ex, ve->var);
+                    // Note: we cannot use f directly, because further overload resolution
+                    // through the supplied 'this' may cause different result.
+                    goto Lagain;
+                }
+                else if (isNeedThisScope(sc, exp->f))
+                {
+                    exp->error("need 'this' for '%s' of type '%s'", exp->f->toChars(), exp->f->type->toChars());
+                    return setError();
+                }
+            }
+
+            exp->checkDeprecated(sc, exp->f);
+            exp->checkPurity(sc, exp->f);
+            exp->checkSafety(sc, exp->f);
+            exp->checkNogc(sc, exp->f);
+            checkAccess(exp->loc, sc, NULL, exp->f);
+            if (exp->f->checkNestedReference(sc, exp->loc))
+                return setError();
+
+            ethis = NULL;
+            tthis = NULL;
+
+            if (ve->hasOverloads)
+            {
+                exp->e1 = new VarExp(ve->loc, exp->f, false);
+                exp->e1->type = exp->f->type;
+            }
+            t1 = exp->f->type;
+        }
+        assert(t1->ty == Tfunction);
+
+        Expression *argprefix;
+        if (!exp->arguments)
+            exp->arguments = new Expressions();
+        if (functionParameters(exp->loc, sc, (TypeFunction *)(t1), tthis, exp->arguments, exp->f, &exp->type, &argprefix))
+            return setError();
+
+        if (!exp->type)
+        {
+            exp->e1 = e1org;     // Bugzilla 10922, avoid recursive expression printing
+            exp->error("forward reference to inferred return type of function call '%s'", exp->toChars());
+            return setError();
+        }
+
+        if (exp->f && exp->f->tintro)
+        {
+            Type *t = exp->type;
+            int offset = 0;
+            TypeFunction *tf = (TypeFunction *)exp->f->tintro;
+
+            if (tf->next->isBaseOf(t, &offset) && offset)
+            {
+                exp->type = tf->next;
+                result = Expression::combine(argprefix, exp->castTo(sc, t));
+                return;
+            }
+        }
+
+        // Handle the case of a direct lambda call
+        if (exp->f && exp->f->isFuncLiteralDeclaration() &&
+            sc->func && !sc->intypeof)
+        {
+            exp->f->tookAddressOf = 0;
+        }
+
+        result = Expression::combine(argprefix, exp);
+    }
+
+    void visit(AddrExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("AddrExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = unaSemantic(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        int wasCond = exp->e1->op == TOKquestion;
+        if (exp->e1->op == TOKdotti)
+        {
+            DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)exp->e1;
+            TemplateInstance *ti = dti->ti;
+            {
+                //assert(ti->needsTypeInference(sc));
+                ti->semantic(sc);
+                if (!ti->inst || ti->errors)    // if template failed to expand
+                    return setError();
+                Dsymbol *s = ti->toAlias();
+                FuncDeclaration *f = s->isFuncDeclaration();
+                if (f)
+                {
+                    exp->e1 = new DotVarExp(exp->e1->loc, dti->e1, f);
+                    exp->e1 = semantic(exp->e1, sc);
+                }
+            }
+        }
+        else if (exp->e1->op == TOKscope)
+        {
+            TemplateInstance *ti = ((ScopeExp *)exp->e1)->sds->isTemplateInstance();
+            if (ti)
+            {
+                //assert(ti->needsTypeInference(sc));
+                ti->semantic(sc);
+                if (!ti->inst || ti->errors)    // if template failed to expand
+                    return setError();
+                Dsymbol *s = ti->toAlias();
+                FuncDeclaration *f = s->isFuncDeclaration();
+                if (f)
+                {
+                    exp->e1 = new VarExp(exp->e1->loc, f);
+                    exp->e1 = semantic(exp->e1, sc);
+                }
+            }
+        }
+        exp->e1 = exp->e1->toLvalue(sc, NULL);
+        if (exp->e1->op == TOKerror)
+        {
+            result = exp->e1;
+            return;
+        }
+        if (checkNonAssignmentArrayOp(exp->e1))
+            return setError();
+
+        if (!exp->e1->type)
+        {
+            exp->error("cannot take address of %s", exp->e1->toChars());
+            return setError();
+        }
+
+        bool hasOverloads = false;
+        if (FuncDeclaration *f = isFuncAddress(exp, &hasOverloads))
+        {
+            if (!hasOverloads && f->checkForwardRef(exp->loc))
+                return setError();
+        }
+        else if (!exp->e1->type->deco)
+        {
+            if (exp->e1->op == TOKvar)
+            {
+                VarExp *ve = (VarExp *)exp->e1;
+                Declaration *d = ve->var;
+                exp->error("forward reference to %s %s", d->kind(), d->toChars());
+            }
+            else
+                exp->error("forward reference to %s", exp->e1->toChars());
+            return setError();
+        }
+
+        exp->type = exp->e1->type->pointerTo();
+
+        // See if this should really be a delegate
+        if (exp->e1->op == TOKdotvar)
+        {
+            DotVarExp *dve = (DotVarExp *)exp->e1;
+            FuncDeclaration *f = dve->var->isFuncDeclaration();
+            if (f)
+            {
+                f = f->toAliasFunc();   // FIXME, should see overlods - Bugzilla 1983
+                if (!dve->hasOverloads)
+                    f->tookAddressOf++;
+
+                Expression *e;
+                if (f->needThis())
+                    e = new DelegateExp(exp->loc, dve->e1, f, dve->hasOverloads);
+                else // It is a function pointer. Convert &v.f() --> (v, &V.f())
+                    e = new CommaExp(exp->loc, dve->e1, new AddrExp(exp->loc, new VarExp(exp->loc, f, dve->hasOverloads)));
+                e = semantic(e, sc);
+                result = e;
+                return;
+            }
+
+            // Look for misaligned pointer in @safe mode
+            if (checkUnsafeAccess(sc, dve, !exp->type->isMutable(), true))
+                return setError();
+
+            if (dve->e1->op == TOKvar && global.params.vsafe)
+            {
+                VarExp *ve = (VarExp *)dve->e1;
+                VarDeclaration *v = ve->var->isVarDeclaration();
+                if (v)
+                {
+                    if (!checkAddressVar(sc, exp, v))
+                        return setError();
+                }
+            }
+            else if ((dve->e1->op == TOKthis || dve->e1->op == TOKsuper) && global.params.vsafe)
+            {
+                ThisExp *ve = (ThisExp *)dve->e1;
+                VarDeclaration *v = ve->var->isVarDeclaration();
+                if (v && v->storage_class & STCref)
+                {
+                    if (!checkAddressVar(sc, exp, v))
+                        return setError();
+                }
+            }
+        }
+        else if (exp->e1->op == TOKvar)
+        {
+            VarExp *ve = (VarExp *)exp->e1;
+
+            VarDeclaration *v = ve->var->isVarDeclaration();
+            if (v)
+            {
+                if (!checkAddressVar(sc, exp, v))
+                    return setError();
+
+                ve->checkPurity(sc, v);
+            }
+
+            FuncDeclaration *f = ve->var->isFuncDeclaration();
+            if (f)
+            {
+                /* Because nested functions cannot be overloaded,
+                 * mark here that we took its address because castTo()
+                 * may not be called with an exact match.
+                 */
+                if (!ve->hasOverloads || f->isNested())
+                    f->tookAddressOf++;
+                if (f->isNested())
+                {
+                    if (f->isFuncLiteralDeclaration())
+                    {
+                        if (!f->FuncDeclaration::isNested())
+                        {
+                            /* Supply a 'null' for a this pointer if no this is available
+                            */
+                            Expression *e = new DelegateExp(exp->loc, new NullExp(exp->loc, Type::tnull), f, ve->hasOverloads);
+                            e = semantic(e, sc);
+                            result = e;
+                            return;
+                        }
+                    }
+                    Expression *e = new DelegateExp(exp->loc, exp->e1, f, ve->hasOverloads);
+                    e = semantic(e, sc);
+                    result = e;
+                    return;
+                }
+                if (f->needThis())
+                {
+                    if (hasThis(sc))
+                    {
+                        /* Should probably supply 'this' after overload resolution,
+                         * not before.
+                         */
+                        Expression *ethis = new ThisExp(exp->loc);
+                        Expression *e = new DelegateExp(exp->loc, ethis, f, ve->hasOverloads);
+                        e = semantic(e, sc);
+                        result = e;
+                        return;
+                    }
+                    if (sc->func && !sc->intypeof)
+                    {
+                        if (sc->func->setUnsafe())
+                        {
+                            exp->error("'this' reference necessary to take address of member %s in @safe function %s",
+                                f->toChars(), sc->func->toChars());
+                        }
+                    }
+                }
+            }
+        }
+        else if ((exp->e1->op == TOKthis || exp->e1->op == TOKsuper) && global.params.vsafe)
+        {
+            ThisExp *ve = (ThisExp *)exp->e1;
+            VarDeclaration *v = ve->var->isVarDeclaration();
+            if (v)
+            {
+                if (!checkAddressVar(sc, exp, v))
+                    return setError();
+            }
+        }
+        else if (exp->e1->op == TOKcall)
+        {
+            CallExp *ce = (CallExp *)exp->e1;
+            if (ce->e1->type->ty == Tfunction)
+            {
+                TypeFunction *tf = (TypeFunction *)ce->e1->type;
+                if (tf->isref && sc->func && !sc->intypeof && sc->func->setUnsafe())
+                {
+                    exp->error("cannot take address of ref return of %s() in @safe function %s",
+                        ce->e1->toChars(), sc->func->toChars());
+                }
+            }
+        }
+        else if (exp->e1->op == TOKindex)
+        {
+            /* For:
+             *   int[3] a;
+             *   &a[i]
+             * check 'a' the same as for a regular variable
+             */
+            IndexExp *ei = (IndexExp *)exp->e1;
+            Type *tyi = ei->e1->type->toBasetype();
+            if (tyi->ty == Tsarray && ei->e1->op == TOKvar)
+            {
+                VarExp *ve = (VarExp *)ei->e1;
+                VarDeclaration *v = ve->var->isVarDeclaration();
+                if (v)
+                {
+                    if (!checkAddressVar(sc, exp, v))
+                        return setError();
+
+                    ve->checkPurity(sc, v);
+                }
+            }
+        }
+        else if (wasCond)
+        {
+            /* a ? b : c was transformed to *(a ? &b : &c), but we still
+             * need to do safety checks
+             */
+            assert(exp->e1->op == TOKstar);
+            PtrExp *pe = (PtrExp *)exp->e1;
+            assert(pe->e1->op == TOKquestion);
+            CondExp *ce = (CondExp *)pe->e1;
+            assert(ce->e1->op == TOKaddress);
+            assert(ce->e2->op == TOKaddress);
+
+            // Re-run semantic on the address expressions only
+            ce->e1->type = NULL;
+            ce->e1 = semantic(ce->e1, sc);
+            ce->e2->type = NULL;
+            ce->e2 = semantic(ce->e2, sc);
+        }
+
+        result = exp->optimize(WANTvalue);
+    }
+
+    void visit(PtrExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("PtrExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        Type *tb = exp->e1->type->toBasetype();
+        switch (tb->ty)
+        {
+            case Tpointer:
+                exp->type = ((TypePointer *)tb)->next;
+                break;
+
+            case Tsarray:
+            case Tarray:
+                exp->error("using * on an array is no longer supported; use *(%s).ptr instead", exp->e1->toChars());
+                exp->type = ((TypeArray *)tb)->next;
+                exp->e1 = exp->e1->castTo(sc, exp->type->pointerTo());
+                break;
+
+            default:
+                exp->error("can only * a pointer, not a '%s'", exp->e1->type->toChars());
+            case Terror:
+                return setError();
+        }
+        if (exp->checkValue())
+            return setError();
+
+        result = exp;
+    }
+
+    void visit(NegExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("NegExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        exp->type = exp->e1->type;
+        Type *tb = exp->type->toBasetype();
+        if (tb->ty == Tarray || tb->ty == Tsarray)
+        {
+            if (!isArrayOpValid(exp->e1))
+            {
+                exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+                return setError();
+            }
+            result = exp;
+            return;
+        }
+
+        if (!Target::isVectorOpSupported(tb, exp->op))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        if (exp->e1->checkNoBool())
+            return setError();
+        if (exp->e1->checkArithmetic())
+            return setError();
+
+        result = exp;
+    }
+
+    void visit(UAddExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("UAddExp::semantic('%s')\n", exp->toChars());
+#endif
+        assert(!exp->type);
+
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (!Target::isVectorOpSupported(exp->e1->type->toBasetype(), exp->op))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        if (exp->e1->checkNoBool())
+            return setError();
+        if (exp->e1->checkArithmetic())
+            return setError();
+
+        result = exp->e1;
+    }
+
+    void visit(ComExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        exp->type = exp->e1->type;
+        Type *tb = exp->type->toBasetype();
+        if (tb->ty == Tarray || tb->ty == Tsarray)
+        {
+            if (!isArrayOpValid(exp->e1))
+            {
+                exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+                return setError();
+            }
+            result = exp;
+            return;
+        }
+
+        if (!Target::isVectorOpSupported(tb, exp->op))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        if (exp->e1->checkNoBool())
+            return setError();
+        if (exp->e1->checkIntegral())
+            return setError();
+
+        result = exp;
+    }
+
+    void visit(NotExp *e)
+    {
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+
+        setNoderefOperand(e);
+
+        // Note there is no operator overload
+        if (Expression *ex = unaSemantic(e, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+        if (e->e1->op == TOKtype)
+            e->e1 = resolveAliasThis(sc, e->e1);
+
+        e->e1 = resolveProperties(sc, e->e1);
+        e->e1 = e->e1->toBoolean(sc);
+        if (e->e1->type == Type::terror)
+        {
+            result = e->e1;
+            return;
+        }
+
+        if (!Target::isVectorOpSupported(e->e1->type->toBasetype(), e->op))
+        {
+            result = e->incompatibleTypes();
+            return;
+        }
+        // Bugzilla 13910: Today NotExp can take an array as its operand.
+        if (checkNonAssignmentArrayOp(e->e1))
+            return setError();
+
+        e->type = Type::tbool;
+        result = e;
+    }
+
+    void visit(DeleteExp *exp)
+    {
+        if (Expression *ex = unaSemantic(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        exp->e1 = resolveProperties(sc, exp->e1);
+        exp->e1 = exp->e1->modifiableLvalue(sc, NULL);
+        if (exp->e1->op == TOKerror)
+        {
+            result = exp->e1;
+            return;
+        }
+        exp->type = Type::tvoid;
+
+        AggregateDeclaration *ad = NULL;
+        Type *tb = exp->e1->type->toBasetype();
+        switch (tb->ty)
+        {   case Tclass:
+            {
+                ClassDeclaration *cd = ((TypeClass *)tb)->sym;
+
+                if (cd->isCOMinterface())
+                {   /* Because COM classes are deleted by IUnknown.Release()
+                */
+                    exp->error("cannot delete instance of COM interface %s", cd->toChars());
+                    return setError();
+                }
+
+                ad = cd;
+                break;
+            }
+            case Tpointer:
+            tb = ((TypePointer *)tb)->next->toBasetype();
+            if (tb->ty == Tstruct)
+            {
+                ad = ((TypeStruct *)tb)->sym;
+                FuncDeclaration *f = ad->aggDelete;
+                FuncDeclaration *fd = ad->dtor;
+
+                if (!f)
+                {
+                    semanticTypeInfo(sc, tb);
+                    break;
+                }
+
+                /* Construct:
+                 *      ea = copy e1 to a tmp to do side effects only once
+                 *      eb = call destructor
+                 *      ec = call deallocator
+                 */
+                Expression *ea = NULL;
+                Expression *eb = NULL;
+                Expression *ec = NULL;
+                VarDeclaration *v = NULL;
+
+                if (fd && f)
+                {
+                    v = copyToTemp(0, "__tmpea", exp->e1);
+                    v->semantic(sc);
+                    ea = new DeclarationExp(exp->loc, v);
+                    ea->type = v->type;
+                }
+
+                if (fd)
+                {
+                    Expression *e = ea ? new VarExp(exp->loc, v) : exp->e1;
+                    e = new DotVarExp(Loc(), e, fd, false);
+                    eb = new CallExp(exp->loc, e);
+                    eb = semantic(eb, sc);
+                }
+
+                if (f)
+                {
+                    Type *tpv = Type::tvoid->pointerTo();
+                    Expression *e = ea ? new VarExp(exp->loc, v) : exp->e1->castTo(sc, tpv);
+                    e = new CallExp(exp->loc, new VarExp(exp->loc, f, false), e);
+                    ec = semantic(e, sc);
+                }
+                ea = Expression::combine(ea, eb);
+                ea = Expression::combine(ea, ec);
+                assert(ea);
+                result = ea;
+                return;
+            }
+            break;
+
+            case Tarray:
+            {
+                Type *tv = tb->nextOf()->baseElemOf();
+                if (tv->ty == Tstruct)
+                {
+                    ad = ((TypeStruct *)tv)->sym;
+                    if (ad->dtor)
+                        semanticTypeInfo(sc, ad->type);
+                }
+                break;
+            }
+            default:
+            exp->error("cannot delete type %s", exp->e1->type->toChars());
+            return setError();
+        }
+
+        bool err = false;
+        if (ad)
+        {
+            if (ad->dtor)
+            {
+                err |= exp->checkPurity(sc, ad->dtor);
+                err |= exp->checkSafety(sc, ad->dtor);
+                err |= exp->checkNogc(sc, ad->dtor);
+            }
+            if (ad->aggDelete && tb->ty != Tarray)
+            {
+                err |= exp->checkPurity(sc, ad->aggDelete);
+                err |= exp->checkSafety(sc, ad->aggDelete);
+                err |= exp->checkNogc(sc, ad->aggDelete);
+            }
+            if (err)
+                return setError();
+        }
+
+        if (!sc->intypeof && sc->func &&
+            !exp->isRAII &&
+            sc->func->setUnsafe())
+        {
+            exp->error("%s is not @safe but is used in @safe function %s", exp->toChars(), sc->func->toChars());
+            err = true;
+        }
+        if (err)
+            return setError();
+
+        result = exp;
+    }
+
+    void visit(CastExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("CastExp::semantic('%s')\n", exp->toChars());
+#endif
+        //static int x; assert(++x < 10);
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (exp->to)
+        {
+            exp->to = exp->to->semantic(exp->loc, sc);
+            if (exp->to == Type::terror)
+                return setError();
+
+            if (!exp->to->hasPointers())
+                setNoderefOperand(exp);
+
+            // When e1 is a template lambda, this cast may instantiate it with
+            // the type 'to'.
+            exp->e1 = inferType(exp->e1, exp->to);
+        }
+
+        if (Expression *ex = unaSemantic(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e1x = resolveProperties(sc, exp->e1);
+        if (e1x->op == TOKerror)
+        {
+            result = e1x;
+            return;
+        }
+        if (e1x->checkType())
+            return setError();
+        exp->e1 = e1x;
+
+        if (!exp->e1->type)
+        {
+            exp->error("cannot cast %s", exp->e1->toChars());
+            return setError();
+        }
+
+        if (!exp->to)    // Handle cast(const) and cast(immutable), etc.
+        {
+            exp->to = exp->e1->type->castMod(exp->mod);
+            exp->to = exp->to->semantic(exp->loc, sc);
+            if (exp->to == Type::terror)
+                return setError();
+        }
+
+        if (exp->to->ty == Ttuple)
+        {
+            exp->error("cannot cast %s to tuple type %s", exp->e1->toChars(), exp->to->toChars());
+            return setError();
+        }
+        if (exp->e1->type->ty != Tvoid ||
+            exp->e1->op == TOKfunction && exp->to->ty == Tvoid ||
+            exp->e1->op == TOKtype ||
+            exp->e1->op == TOKtemplate)
+        {
+            if (exp->e1->checkValue())
+                return setError();
+        }
+
+        // cast(void) is used to mark e1 as unused, so it is safe
+        if (exp->to->ty == Tvoid)
+        {
+            exp->type = exp->to;
+            result = exp;
+            return;
+        }
+
+        if (!exp->to->equals(exp->e1->type) && exp->mod == (unsigned char)~0)
+        {
+            if (Expression *e = exp->op_overload(sc))
+            {
+                result = e->implicitCastTo(sc, exp->to);
+                return;
+            }
+        }
+
+        Type *t1b = exp->e1->type->toBasetype();
+        Type *tob = exp->to->toBasetype();
+
+        if (tob->ty == Tstruct && !tob->equals(t1b))
+        {
+            /* Look to replace:
+             *  cast(S)t
+             * with:
+             *  S(t)
+             */
+
+            // Rewrite as to.call(e1)
+            Expression *e = new TypeExp(exp->loc, exp->to);
+            e = new CallExp(exp->loc, e, exp->e1);
+            e = trySemantic(e, sc);
+            if (e)
+            {
+                result = e;
+                return;
+            }
+        }
+
+        if (!t1b->equals(tob) && (t1b->ty == Tarray || t1b->ty == Tsarray))
+        {
+            if (checkNonAssignmentArrayOp(exp->e1))
+                return setError();
+        }
+
+        // Look for casting to a vector type
+        if (tob->ty == Tvector && t1b->ty != Tvector)
+        {
+            result = new VectorExp(exp->loc, exp->e1, exp->to);
+            return;
+        }
+
+        Expression *ex = exp->e1->castTo(sc, exp->to);
+        if (ex->op == TOKerror)
+        {
+            result = ex;
+            return;
+        }
+
+        // Check for unsafe casts
+        if (sc->func && !sc->intypeof)
+        {
+            // Disallow unsafe casts
+
+            // Implicit conversions are always safe
+            if (t1b->implicitConvTo(tob))
+                goto Lsafe;
+
+            if (!tob->hasPointers())
+                goto Lsafe;
+
+            if (tob->ty == Tclass && t1b->ty == Tclass)
+            {
+                ClassDeclaration *cdfrom = t1b->isClassHandle();
+                ClassDeclaration *cdto   = tob->isClassHandle();
+
+                int offset;
+                if (!cdfrom->isBaseOf(cdto, &offset))
+                    goto Lunsafe;
+
+                if (cdfrom->isCPPinterface() ||
+                    cdto->isCPPinterface())
+                    goto Lunsafe;
+
+                if (!MODimplicitConv(t1b->mod, tob->mod))
+                    goto Lunsafe;
+                goto Lsafe;
+            }
+
+            if (tob->ty == Tarray && t1b->ty == Tsarray)    // Bugzilla 12502
+                t1b = t1b->nextOf()->arrayOf();
+
+            if (tob->ty == Tarray   && t1b->ty == Tarray ||
+                tob->ty == Tpointer && t1b->ty == Tpointer)
+            {
+                Type* tobn = tob->nextOf()->toBasetype();
+                Type* t1bn = t1b->nextOf()->toBasetype();
+
+                /* From void[] to anything mutable is unsafe because:
+                 *  int*[] api;
+                 *  void[] av = api;
+                 *  int[] ai = cast(int[]) av;
+                 *  ai[0] = 7;
+                 *  *api[0] crash!
+                 */
+                if (t1bn->ty == Tvoid && tobn->isMutable())
+                {
+                    if (tob->ty == Tarray && ex->op == TOKarrayliteral)
+                        goto Lsafe;
+                    goto Lunsafe;
+                }
+
+                // If the struct is opaque we don't know about the struct members and the cast becomes unsafe
+                if (tobn->ty == Tstruct && !((TypeStruct *)tobn)->sym->members ||
+                    t1bn->ty == Tstruct && !((TypeStruct *)t1bn)->sym->members)
+                    goto Lunsafe;
+
+                bool t1pointers = t1bn->hasPointers();
+                bool topointers = tobn->hasPointers();
+
+                if (t1pointers && !topointers && tobn->isMutable())
+                    goto Lunsafe;
+
+                if (!t1pointers && topointers)
+                    goto Lunsafe;
+
+                if (!topointers &&
+                    tobn->ty != Tfunction && t1bn->ty != Tfunction &&
+                    (tob->ty == Tarray || tobn->size() <= t1bn->size()) &&
+                    MODimplicitConv(t1bn->mod, tobn->mod))
+                {
+                    goto Lsafe;
+                }
+            }
+
+        Lunsafe:
+            if (sc->func->setUnsafe())
+            {
+                exp->error("cast from %s to %s not allowed in safe code", exp->e1->type->toChars(), exp->to->toChars());
+                return setError();
+            }
+        }
+
+    Lsafe:
+        result = ex;
+    }
+
+    void visit(VectorExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("VectorExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        exp->e1 = semantic(exp->e1, sc);
+        exp->type = exp->to->semantic(exp->loc, sc);
+        if (exp->e1->op == TOKerror || exp->type->ty == Terror)
+        {
+            result = exp->e1;
+            return;
+        }
+
+        Type *tb = exp->type->toBasetype();
+        assert(tb->ty == Tvector);
+        TypeVector *tv = (TypeVector *)tb;
+        Type *te = tv->elementType();
+        exp->dim = (int)(tv->size(exp->loc) / te->size(exp->loc));
+
+        exp->e1 = exp->e1->optimize(WANTvalue);
+        bool res = false;
+        if (exp->e1->op == TOKarrayliteral)
+        {
+            for (size_t i = 0; i < exp->dim; i++)
+            {
+                // Do not stop on first error - check all AST nodes even if error found
+                res |= checkVectorElem(exp, ((ArrayLiteralExp *)exp->e1)->getElement(i));
+            }
+        }
+        else if (exp->e1->type->ty == Tvoid)
+            res = checkVectorElem(exp, exp->e1);
+
+        Expression *e = exp;
+        if (res)
+            e = new ErrorExp();
+        result = e;
+    }
+
+    void visit(SliceExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("SliceExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        // operator overloading should be handled in ArrayExp already.
+
+        if (Expression *ex = unaSemantic(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        exp->e1 = resolveProperties(sc, exp->e1);
+        if (exp->e1->op == TOKtype && exp->e1->type->ty != Ttuple)
+        {
+            if (exp->lwr || exp->upr)
+            {
+                exp->error("cannot slice type '%s'", exp->e1->toChars());
+                return setError();
+            }
+            Expression *e = new TypeExp(exp->loc, exp->e1->type->arrayOf());
+            result = semantic(e, sc);
+            return;
+        }
+        if (!exp->lwr && !exp->upr)
+        {
+            if (exp->e1->op == TOKarrayliteral)
+            {
+                // Convert [a,b,c][] to [a,b,c]
+                Type *t1b = exp->e1->type->toBasetype();
+                Expression *e = exp->e1;
+                if (t1b->ty == Tsarray)
+                {
+                    e = e->copy();
+                    e->type = t1b->nextOf()->arrayOf();
+                }
+                result = e;
+                return;
+            }
+            if (exp->e1->op == TOKslice)
+            {
+                // Convert e[][] to e[]
+                SliceExp *se = (SliceExp *)exp->e1;
+                if (!se->lwr && !se->upr)
+                {
+                    result = se;
+                    return;
+                }
+            }
+            if (isArrayOpOperand(exp->e1))
+            {
+                // Convert (a[]+b[])[] to a[]+b[]
+                result = exp->e1;
+                return;
+            }
+        }
+        if (exp->e1->op == TOKerror)
+        {
+            result = exp->e1;
+            return;
+        }
+        if (exp->e1->type->ty == Terror)
+            return setError();
+
+        Type *t1b = exp->e1->type->toBasetype();
+        if (t1b->ty == Tpointer)
+        {
+            if (((TypePointer *)t1b)->next->ty == Tfunction)
+            {
+                exp->error("cannot slice function pointer %s", exp->e1->toChars());
+                return setError();
+            }
+            if (!exp->lwr || !exp->upr)
+            {
+                exp->error("need upper and lower bound to slice pointer");
+                return setError();
+            }
+            if (sc->func && !sc->intypeof && sc->func->setUnsafe())
+            {
+                exp->error("pointer slicing not allowed in safe functions");
+                return setError();
+            }
+        }
+        else if (t1b->ty == Tarray)
+        {
+        }
+        else if (t1b->ty == Tsarray)
+        {
+        }
+        else if (t1b->ty == Ttuple)
+        {
+            if (!exp->lwr && !exp->upr)
+            {
+                result = exp->e1;
+                return;
+            }
+            if (!exp->lwr || !exp->upr)
+            {
+                exp->error("need upper and lower bound to slice tuple");
+                return setError();
+            }
+        }
+        else if (t1b->ty == Tvector)
+        {
+            // Convert e1 to corresponding static array
+            TypeVector *tv1 = (TypeVector *)t1b;
+            t1b = tv1->basetype;
+            t1b = t1b->castMod(tv1->mod);
+            exp->e1->type = t1b;
+        }
+        else
+        {
+            exp->error("%s cannot be sliced with []",
+                t1b->ty == Tvoid ? exp->e1->toChars() : t1b->toChars());
+            return setError();
+        }
+
+        /* Run semantic on lwr and upr.
+        */
+        Scope *scx = sc;
+        if (t1b->ty == Tsarray || t1b->ty == Tarray || t1b->ty == Ttuple)
+        {
+            // Create scope for 'length' variable
+            ScopeDsymbol *sym = new ArrayScopeSymbol(sc, exp);
+            sym->loc = exp->loc;
+            sym->parent = sc->scopesym;
+            sc = sc->push(sym);
+        }
+        if (exp->lwr)
+        {
+            if (t1b->ty == Ttuple) sc = sc->startCTFE();
+            exp->lwr = semantic(exp->lwr, sc);
+            exp->lwr = resolveProperties(sc, exp->lwr);
+            if (t1b->ty == Ttuple) sc = sc->endCTFE();
+            exp->lwr = exp->lwr->implicitCastTo(sc, Type::tsize_t);
+        }
+        if (exp->upr)
+        {
+            if (t1b->ty == Ttuple) sc = sc->startCTFE();
+            exp->upr = semantic(exp->upr, sc);
+            exp->upr = resolveProperties(sc, exp->upr);
+            if (t1b->ty == Ttuple) sc = sc->endCTFE();
+            exp->upr = exp->upr->implicitCastTo(sc, Type::tsize_t);
+        }
+        if (sc != scx)
+            sc = sc->pop();
+        if (exp->lwr && exp->lwr->type == Type::terror ||
+            exp->upr && exp->upr->type == Type::terror)
+        {
+            return setError();
+        }
+
+        if (t1b->ty == Ttuple)
+        {
+            exp->lwr = exp->lwr->ctfeInterpret();
+            exp->upr = exp->upr->ctfeInterpret();
+            uinteger_t i1 = exp->lwr->toUInteger();
+            uinteger_t i2 = exp->upr->toUInteger();
+
+            TupleExp *te;
+            TypeTuple *tup;
+            size_t length;
+            if (exp->e1->op == TOKtuple)         // slicing an expression tuple
+            {
+                te = (TupleExp *)exp->e1;
+                tup = NULL;
+                length = te->exps->dim;
+            }
+            else if (exp->e1->op == TOKtype)     // slicing a type tuple
+            {
+                te = NULL;
+                tup = (TypeTuple *)t1b;
+                length = Parameter::dim(tup->arguments);
+            }
+            else
+                assert(0);
+
+            if (i2 < i1 || length < i2)
+            {
+                exp->error("string slice [%llu .. %llu] is out of bounds", i1, i2);
+                return setError();
+            }
+
+            size_t j1 = (size_t) i1;
+            size_t j2 = (size_t) i2;
+            Expression *e;
+            if (exp->e1->op == TOKtuple)
+            {
+                Expressions *exps = new Expressions;
+                exps->setDim(j2 - j1);
+                for (size_t i = 0; i < j2 - j1; i++)
+                {
+                    (*exps)[i] = (*te->exps)[j1 + i];
+                }
+                e = new TupleExp(exp->loc, te->e0, exps);
+            }
+            else
+            {
+                Parameters *args = new Parameters;
+                args->reserve(j2 - j1);
+                for (size_t i = j1; i < j2; i++)
+                {
+                    Parameter *arg = Parameter::getNth(tup->arguments, i);
+                    args->push(arg);
+                }
+                e = new TypeExp(exp->e1->loc, new TypeTuple(args));
+            }
+            e = semantic(e, sc);
+            result = e;
+            return;
+        }
+
+        exp->type = t1b->nextOf()->arrayOf();
+        // Allow typedef[] -> typedef[]
+        if (exp->type->equals(t1b))
+            exp->type = exp->e1->type;
+
+        if (exp->lwr && exp->upr)
+        {
+            exp->lwr = exp->lwr->optimize(WANTvalue);
+            exp->upr = exp->upr->optimize(WANTvalue);
+
+            IntRange lwrRange = getIntRange(exp->lwr);
+            IntRange uprRange = getIntRange(exp->upr);
+
+            if (t1b->ty == Tsarray || t1b->ty == Tarray)
+            {
+                Expression *el = new ArrayLengthExp(exp->loc, exp->e1);
+                el = semantic(el, sc);
+                el = el->optimize(WANTvalue);
+                if (el->op == TOKint64)
+                {
+                    dinteger_t length = el->toInteger();
+                    IntRange bounds(SignExtendedNumber(0), SignExtendedNumber(length));
+                    exp->upperIsInBounds = bounds.contains(uprRange);
+                }
+            }
+            else if (t1b->ty == Tpointer)
+            {
+                exp->upperIsInBounds = true;
+            }
+            else
+                assert(0);
+
+            exp->lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
+
+            //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", upperIsInBounds, lowerIsLessThanUpper);
+        }
+
+        result = exp;
+    }
+
+    void visit(ArrayLengthExp *e)
+    {
+#if LOGSEMANTIC
+        printf("ArrayLengthExp::semantic('%s')\n", e->toChars());
+#endif
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+
+        if (Expression *ex = unaSemantic(e, sc))
+        {
+            result = ex;
+            return;
+        }
+        e->e1 = resolveProperties(sc, e->e1);
+
+        e->type = Type::tsize_t;
+        result = e;
+    }
+
+    void visit(IntervalExp *e)
+    {
+#if LOGSEMANTIC
+        printf("IntervalExp::semantic('%s')\n", e->toChars());
+#endif
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+
+        Expression *le = e->lwr;
+        le = semantic(le, sc);
+        le = resolveProperties(sc, le);
+
+        Expression *ue = e->upr;
+        ue = semantic(ue, sc);
+        ue = resolveProperties(sc, ue);
+
+        if (le->op == TOKerror)
+        {
+            result = le;
+            return;
+        }
+        if (ue->op == TOKerror)
+        {
+            result = ue;
+            return;
+        }
+
+        e->lwr = le;
+        e->upr = ue;
+
+        e->type = Type::tvoid;
+        result = e;
+    }
+
+    void visit(DelegatePtrExp *e)
+    {
+#if LOGSEMANTIC
+        printf("DelegatePtrExp::semantic('%s')\n", e->toChars());
+#endif
+        if (!e->type)
+        {
+            unaSemantic(e, sc);
+            e->e1 = resolveProperties(sc, e->e1);
+
+            if (e->e1->op == TOKerror)
+            {
+                result = e->e1;
+                return;
+            }
+            e->type = Type::tvoidptr;
+        }
+        result = e;
+    }
+
+    void visit(DelegateFuncptrExp *e)
+    {
+#if LOGSEMANTIC
+        printf("DelegateFuncptrExp::semantic('%s')\n", e->toChars());
+#endif
+        if (!e->type)
+        {
+            unaSemantic(e, sc);
+            e->e1 = resolveProperties(sc, e->e1);
+
+            if (e->e1->op == TOKerror)
+            {
+                result = e->e1;
+                return;
+            }
+            e->type = e->e1->type->nextOf()->pointerTo();
+        }
+        result = e;
+    }
+
+    void visit(ArrayExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("ArrayExp::semantic('%s')\n", exp->toChars());
+#endif
+        assert(!exp->type);
+
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (isAggregate(exp->e1->type))
+            exp->error("no [] operator overload for type %s", exp->e1->type->toChars());
+        else
+            exp->error("only one index allowed to index %s", exp->e1->type->toChars());
+        return setError();
+    }
+
+    void visit(DotExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("DotExp::semantic('%s')\n", exp->toChars());
+        if (exp->type) printf("\ttype = %s\n", exp->type->toChars());
+#endif
+        exp->e1 = semantic(exp->e1, sc);
+        exp->e2 = semantic(exp->e2, sc);
+        if (exp->e2->op == TOKscope)
+        {
+            ScopeExp *se = (ScopeExp *)exp->e2;
+            TemplateDeclaration *td = se->sds->isTemplateDeclaration();
+            if (td)
+            {
+                Expression *e = new DotTemplateExp(exp->loc, exp->e1, td);
+                e = semantic(e, sc);
+                result = e;
+                return;
+            }
+        }
+        if (exp->e2->op == TOKtype)
+        {
+            result = exp->e2;
+            return;
+        }
+        if (!exp->type)
+            exp->type = exp->e2->type;
+        result = exp;
+    }
+
+    void visit(CommaExp *e)
+    {
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
+
+        // Allow `((a,b),(x,y))`
+        if (e->allowCommaExp)
+        {
+            if (e->e1 && e->e1->op == TOKcomma)
+                ((CommaExp *)e->e1)->allowCommaExp = true;
+            if (e->e2 && e->e2->op == TOKcomma)
+                ((CommaExp *)e->e2)->allowCommaExp = true;
+        }
+
+        if (Expression *ex = binSemanticProp(e, sc))
+        {
+            result = ex;
+            return;
+        }
+        e->e1 = e->e1->addDtorHook(sc);
+
+        if (checkNonAssignmentArrayOp(e->e1))
+            return setError();
+
+        e->type = e->e2->type;
+        if (e->type != Type::tvoid && !e->allowCommaExp && !e->isGenerated)
+            e->deprecation("Using the result of a comma expression is deprecated");
+        result = e;
+    }
+
+    void visit(IndexExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("IndexExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        // operator overloading should be handled in ArrayExp already.
+
+        if (!exp->e1->type)
+            exp->e1 = semantic(exp->e1, sc);
+        assert(exp->e1->type);           // semantic() should already be run on it
+        if (exp->e1->op == TOKtype && exp->e1->type->ty != Ttuple)
+        {
+            exp->e2 = semantic(exp->e2, sc);
+            exp->e2 = resolveProperties(sc, exp->e2);
+            Type *nt;
+            if (exp->e2->op == TOKtype)
+                nt = new TypeAArray(exp->e1->type, exp->e2->type);
+            else
+                nt = new TypeSArray(exp->e1->type, exp->e2);
+            Expression *e = new TypeExp(exp->loc, nt);
+            result = semantic(e, sc);
+            return;
+        }
+        if (exp->e1->op == TOKerror)
+        {
+            result = exp->e1;
+            return;
+        }
+        if (exp->e1->type->ty == Terror)
+            return setError();
+
+        // Note that unlike C we do not implement the int[ptr]
+
+        Type *t1b = exp->e1->type->toBasetype();
+
+        if (t1b->ty == Tvector)
+        {
+            // Convert e1 to corresponding static array
+            TypeVector *tv1 = (TypeVector *)t1b;
+            t1b = tv1->basetype;
+            t1b = t1b->castMod(tv1->mod);
+            exp->e1->type = t1b;
+        }
+
+        /* Run semantic on e2
+        */
+        Scope *scx = sc;
+        if (t1b->ty == Tsarray || t1b->ty == Tarray || t1b->ty == Ttuple)
+        {
+            // Create scope for 'length' variable
+            ScopeDsymbol *sym = new ArrayScopeSymbol(sc, exp);
+            sym->loc = exp->loc;
+            sym->parent = sc->scopesym;
+            sc = sc->push(sym);
+        }
+        if (t1b->ty == Ttuple) sc = sc->startCTFE();
+        exp->e2 = semantic(exp->e2, sc);
+        exp->e2 = resolveProperties(sc, exp->e2);
+        if (t1b->ty == Ttuple) sc = sc->endCTFE();
+        if (exp->e2->op == TOKtuple)
+        {
+            TupleExp *te = (TupleExp *)exp->e2;
+            if (te->exps && te->exps->dim == 1)
+                exp->e2 = Expression::combine(te->e0, (*te->exps)[0]);  // bug 4444 fix
+        }
+        if (sc != scx)
+            sc = sc->pop();
+        if (exp->e2->type == Type::terror)
+            return setError();
+
+        if (checkNonAssignmentArrayOp(exp->e1))
+            return setError();
+
+        switch (t1b->ty)
+        {
+            case Tpointer:
+                if (((TypePointer *)t1b)->next->ty == Tfunction)
+                {
+                    exp->error("cannot index function pointer %s", exp->e1->toChars());
+                    return setError();
+                }
+                exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
+                if (exp->e2->type == Type::terror)
+                    return setError();
+                exp->e2 = exp->e2->optimize(WANTvalue);
+                if (exp->e2->op == TOKint64 && exp->e2->toInteger() == 0)
+                    ;
+                else if (sc->func && sc->func->setUnsafe())
+                {
+                    exp->error("safe function '%s' cannot index pointer '%s'",
+                        sc->func->toPrettyChars(), exp->e1->toChars());
+                    return setError();
+                }
+                exp->type = ((TypeNext *)t1b)->next;
+                break;
+
+            case Tarray:
+                exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
+                if (exp->e2->type == Type::terror)
+                    return setError();
+                exp->type = ((TypeNext *)t1b)->next;
+                break;
+
+            case Tsarray:
+                {
+                    exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
+                    if (exp->e2->type == Type::terror)
+                        return setError();
+                    exp->type = t1b->nextOf();
+                    break;
+                }
+
+            case Taarray:
+                {
+                    TypeAArray *taa = (TypeAArray *)t1b;
+                    /* We can skip the implicit conversion if they differ only by
+                     * constness (Bugzilla 2684, see also bug 2954b)
+                     */
+                    if (!arrayTypeCompatibleWithoutCasting(exp->e2->loc, exp->e2->type, taa->index))
+                    {
+                        exp->e2 = exp->e2->implicitCastTo(sc, taa->index);        // type checking
+                        if (exp->e2->type == Type::terror)
+                            return setError();
+                    }
+
+                    semanticTypeInfo(sc, taa);
+
+                    exp->type = taa->next;
+                    break;
+                }
+
+            case Ttuple:
+                {
+                    exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
+                    if (exp->e2->type == Type::terror)
+                        return setError();
+                    exp->e2 = exp->e2->ctfeInterpret();
+                    uinteger_t index = exp->e2->toUInteger();
+
+                    TupleExp *te;
+                    TypeTuple *tup;
+                    size_t length;
+                    if (exp->e1->op == TOKtuple)
+                    {
+                        te = (TupleExp *)exp->e1;
+                        tup = NULL;
+                        length = te->exps->dim;
+                    }
+                    else if (exp->e1->op == TOKtype)
+                    {
+                        te = NULL;
+                        tup = (TypeTuple *)t1b;
+                        length = Parameter::dim(tup->arguments);
+                    }
+                    else
+                        assert(0);
+
+                    if (length <= index)
+                    {
+                        exp->error("array index [%llu] is outside array bounds [0 .. %llu]",
+                            index, (ulonglong)length);
+                        return setError();
+                    }
+
+                    Expression *e;
+                    if (exp->e1->op == TOKtuple)
+                    {
+                        e = (*te->exps)[(size_t)index];
+                        e = Expression::combine(te->e0, e);
+                    }
+                    else
+                        e = new TypeExp(exp->e1->loc, Parameter::getNth(tup->arguments, (size_t)index)->type);
+                    result = e;
+                    return;
+                }
+
+            default:
+                exp->error("%s must be an array or pointer type, not %s",
+                    exp->e1->toChars(), exp->e1->type->toChars());
+                return setError();
+        }
+
+        if (t1b->ty == Tsarray || t1b->ty == Tarray)
+        {
+            Expression *el = new ArrayLengthExp(exp->loc, exp->e1);
+            el = semantic(el, sc);
+            el = el->optimize(WANTvalue);
+            if (el->op == TOKint64)
+            {
+                exp->e2 = exp->e2->optimize(WANTvalue);
+                dinteger_t length = el->toInteger();
+                if (length)
+                {
+                    IntRange bounds(SignExtendedNumber(0), SignExtendedNumber(length - 1));
+                    exp->indexIsInBounds = bounds.contains(getIntRange(exp->e2));
+                }
+            }
+        }
+
+        result = exp;
+    }
+
+    void visit(PostExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("PostExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemantic(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e1x = resolveProperties(sc, exp->e1);
+        if (e1x->op == TOKerror)
+        {
+            result = e1x;
+            return;
+        }
+        exp->e1 = e1x;
+
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (exp->e1->checkReadModifyWrite(exp->op))
+            return setError();
+        if (exp->e1->op == TOKslice)
+        {
+            const char *s = exp->op == TOKplusplus ? "increment" : "decrement";
+            exp->error("cannot post-%s array slice '%s', use pre-%s instead", s, exp->e1->toChars(), s);
+            return setError();
+        }
+
+        exp->e1 = exp->e1->optimize(WANTvalue);
+
+        Type *t1 = exp->e1->type->toBasetype();
+        if (t1->ty == Tclass || t1->ty == Tstruct || exp->e1->op == TOKarraylength)
+        {
+            /* Check for operator overloading,
+             * but rewrite in terms of ++e instead of e++
+             */
+
+            /* If e1 is not trivial, take a reference to it
+            */
+            Expression *de = NULL;
+            if (exp->e1->op != TOKvar && exp->e1->op != TOKarraylength)
+            {
+                // ref v = e1;
+                VarDeclaration *v = copyToTemp(STCref, "__postref", exp->e1);
+                de = new DeclarationExp(exp->loc, v);
+                exp->e1 = new VarExp(exp->e1->loc, v);
+            }
+
+            /* Rewrite as:
+             * auto tmp = e1; ++e1; tmp
+             */
+            VarDeclaration *tmp = copyToTemp(0, "__pitmp", exp->e1);
+            Expression *ea = new DeclarationExp(exp->loc, tmp);
+
+            Expression *eb = exp->e1->syntaxCopy();
+            eb = new PreExp(exp->op == TOKplusplus ? TOKpreplusplus : TOKpreminusminus, exp->loc, eb);
+
+            Expression *ec = new VarExp(exp->loc, tmp);
+
+            // Combine de,ea,eb,ec
+            if (de)
+                ea = new CommaExp(exp->loc, de, ea);
+            e = new CommaExp(exp->loc, ea, eb);
+            e = new CommaExp(exp->loc, e, ec);
+            e = semantic(e, sc);
+            result = e;
+            return;
+        }
+
+        exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
+
+        e = exp;
+        if (exp->e1->checkScalar())
+            return setError();
+        if (exp->e1->checkNoBool())
+            return setError();
+
+        if (exp->e1->type->ty == Tpointer)
+            e = scaleFactor(exp, sc);
+        else
+            exp->e2 = exp->e2->castTo(sc, exp->e1->type);
+        e->type = exp->e1->type;
+        result = e;
+    }
+
+    void visit(PreExp *exp)
+    {
+        Expression *e = exp->op_overload(sc);
+        // printf("PreExp::semantic('%s')\n", exp->toChars());
+
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        // Rewrite as e1+=1 or e1-=1
+        if (exp->op == TOKpreplusplus)
+            e = new AddAssignExp(exp->loc, exp->e1, new IntegerExp(exp->loc, 1, Type::tint32));
+        else
+            e = new MinAssignExp(exp->loc, exp->e1, new IntegerExp(exp->loc, 1, Type::tint32));
+        result = semantic(e, sc);
+    }
+
+    void visit(AssignExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("AssignExp::semantic('%s')\n", exp->toChars());
+#endif
+        //printf("e1->op = %d, '%s'\n", exp->e1->op, Token::toChars(exp->e1->op));
+        //printf("e2->op = %d, '%s'\n", exp->e2->op, Token::toChars(exp->e2->op));
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        Expression *e1old = exp->e1;
+
+        if (exp->e2->op == TOKcomma)
+        {
+            /* Rewrite to get rid of the comma from rvalue
+            */
+            if (!((CommaExp *)exp->e2)->isGenerated)
+                exp->deprecation("Using the result of a comma expression is deprecated");
+            Expression *e0;
+            exp->e2 = Expression::extractLast(exp->e2, &e0);
+            Expression *e = Expression::combine(e0, exp);
+            result = semantic(e, sc);
+            return;
+        }
+
+        /* Look for operator overloading of a[arguments] = e2.
+         * Do it before e1->semantic() otherwise the ArrayExp will have been
+         * converted to unary operator overloading already.
+         */
+        if (exp->e1->op == TOKarray)
+        {
+            Expression *res;
+
+            ArrayExp *ae = (ArrayExp *)exp->e1;
+            ae->e1 = semantic(ae->e1, sc);
+            ae->e1 = resolveProperties(sc, ae->e1);
+            Expression *ae1old = ae->e1;
+
+            const bool maybeSlice =
+                (ae->arguments->dim == 0 ||
+                 ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval);
+            IntervalExp *ie = NULL;
+            if (maybeSlice && ae->arguments->dim)
+            {
+                assert((*ae->arguments)[0]->op == TOKinterval);
+                ie = (IntervalExp *)(*ae->arguments)[0];
+            }
+
+            while (true)
+            {
+                if (ae->e1->op == TOKerror)
+                {
+                    result = ae->e1;
+                    return;
+                }
+                Expression *e0 = NULL;
+                Expression *ae1save = ae->e1;
+                ae->lengthVar = NULL;
+
+                Type *t1b = ae->e1->type->toBasetype();
+                AggregateDeclaration *ad = isAggregate(t1b);
+                if (!ad)
+                    break;
+                if (search_function(ad, Id::indexass))
+                {
+                    // Deal with $
+                    res = resolveOpDollar(sc, ae, &e0);
+                    if (!res)    // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
+                        goto Lfallback;
+                    if (res->op == TOKerror)
+                    {
+                        result = res;
+                        return;
+                    }
+
+                    res = semantic(exp->e2, sc);
+                    if (res->op == TOKerror)
+                    {
+                        result = res;
+                        return;
+                    }
+                    exp->e2 = res;
+
+                    /* Rewrite (a[arguments] = e2) as:
+                     *      a.opIndexAssign(e2, arguments)
+                     */
+                    Expressions *a = (Expressions *)ae->arguments->copy();
+                    a->insert(0, exp->e2);
+                    res = new DotIdExp(exp->loc, ae->e1, Id::indexass);
+                    res = new CallExp(exp->loc, res, a);
+                    if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
+                        res = trySemantic(res, sc);
+                    else
+                        res = semantic(res, sc);
+                    if (res)
+                    {
+                        res = Expression::combine(e0, res);
+                        result = res;
+                        return;
+                    }
+                }
+            Lfallback:
+                if (maybeSlice && search_function(ad, Id::sliceass))
+                {
+                    // Deal with $
+                    res = resolveOpDollar(sc, ae, ie, &e0);
+                    if (res->op == TOKerror)
+                    {
+                        result = res;
+                        return;
+                    }
+
+                    res = semantic(exp->e2, sc);
+                    if (res->op == TOKerror)
+                    {
+                        result = res;
+                        return;
+                    }
+                    exp->e2 = res;
+
+                    /* Rewrite (a[i..j] = e2) as:
+                     *      a.opSliceAssign(e2, i, j)
+                     */
+                    Expressions *a = new Expressions();
+                    a->push(exp->e2);
+                    if (ie)
+                    {
+                        a->push(ie->lwr);
+                        a->push(ie->upr);
+                    }
+                    res = new DotIdExp(exp->loc, ae->e1, Id::sliceass);
+                    res = new CallExp(exp->loc, res, a);
+                    res = semantic(res, sc);
+                    res = Expression::combine(e0, res);
+                    result = res;
+                    return;
+                }
+
+                // No operator overloading member function found yet, but
+                // there might be an alias this to try.
+                if (ad->aliasthis && t1b != ae->att1)
+                {
+                    if (!ae->att1 && t1b->checkAliasThisRec())
+                        ae->att1 = t1b;
+
+                    /* Rewrite (a[arguments] op e2) as:
+                     *      a.aliasthis[arguments] op e2
+                     */
+                    ae->e1 = resolveAliasThis(sc, ae1save, true);
+                    if (ae->e1)
+                        continue;
+                }
+                break;
+            }
+            ae->e1 = ae1old;    // recovery
+            ae->lengthVar = NULL;
+        }
+
+        /* Run exp->e1 semantic.
+         */
+        {
+            Expression *e1x = exp->e1;
+
+            /* With UFCS, e.f = value
+             * Could mean:
+             *      .f(e, value)
+             * or:
+             *      .f(e) = value
+             */
+            if (e1x->op == TOKdotti)
+            {
+                DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)e1x;
+                Expression *e = semanticY(dti, sc, 1);
+                if (!e)
+                {
+                    result = resolveUFCSProperties(sc, e1x, exp->e2);
+                    return;
+                }
+                e1x = e;
+            }
+            else if (e1x->op == TOKdotid)
+            {
+                DotIdExp *die = (DotIdExp *)e1x;
+                Expression *e = semanticY(die, sc, 1);
+                if (e && isDotOpDispatch(e))
+                {
+                    unsigned errors = global.startGagging();
+                    e = resolvePropertiesX(sc, e, exp->e2);
+                    if (global.endGagging(errors))
+                        e = NULL;   /* fall down to UFCS */
+                    else
+                    {
+                        result = e;
+                        return;
+                    }
+                }
+                if (!e)
+                {
+                    result = resolveUFCSProperties(sc, e1x, exp->e2);
+                    return;
+                }
+                e1x = e;
+            }
+            else
+                e1x = semantic(e1x, sc);
+
+            /* We have f = value.
+             * Could mean:
+             *      f(value)
+             * or:
+             *      f() = value
+             */
+            if (Expression *e = resolvePropertiesX(sc, e1x, exp->e2))
+            {
+                result = e;
+                return;
+            }
+            if (e1x->checkRightThis(sc))
+                return setError();
+            exp->e1 = e1x;
+            assert(exp->e1->type);
+        }
+        Type *t1 = exp->e1->type->toBasetype();
+
+        /* Run exp->e2 semantic.
+         * Different from other binary expressions, the analysis of e2
+         * depends on the result of e1 in assignments.
+         */
+        {
+            Expression *e2x = inferType(exp->e2, t1->baseElemOf());
+
+            e2x = semantic(e2x, sc);
+            e2x = resolveProperties(sc, e2x);
+
+            if (e2x->op == TOKtype)
+                e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
+            if (e2x->op == TOKerror)
+            {
+                result = e2x;
+                return;
+            }
+            if (e2x->checkValue())
+                return setError();
+            exp->e2 = e2x;
+        }
+
+        /* Rewrite tuple assignment as a tuple of assignments.
+        */
+        {
+            Expression *e2x = exp->e2;
+
+        Ltupleassign:
+            if (exp->e1->op == TOKtuple && e2x->op == TOKtuple)
+            {
+                TupleExp *tup1 = (TupleExp *)exp->e1;
+                TupleExp *tup2 = (TupleExp *)e2x;
+                size_t dim = tup1->exps->dim;
+                Expression *e = NULL;
+                if (dim != tup2->exps->dim)
+                {
+                    exp->error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim);
+                    return setError();
+                }
+                if (dim == 0)
+                {
+                    e = new IntegerExp(exp->loc, 0, Type::tint32);
+                    e = new CastExp(exp->loc, e, Type::tvoid);   // avoid "has no effect" error
+                    e = Expression::combine(Expression::combine(tup1->e0, tup2->e0), e);
+                }
+                else
+                {
+                    Expressions *exps = new Expressions;
+                    exps->setDim(dim);
+                    for (size_t i = 0; i < dim; i++)
+                    {
+                        Expression *ex1 = (*tup1->exps)[i];
+                        Expression *ex2 = (*tup2->exps)[i];
+                        (*exps)[i] = new AssignExp(exp->loc, ex1, ex2);
+                    }
+                    e = new TupleExp(exp->loc, Expression::combine(tup1->e0, tup2->e0), exps);
+                }
+                result = semantic(e, sc);
+                return;
+            }
+
+            /* Look for form: e1 = e2->aliasthis.
+             */
+            if (exp->e1->op == TOKtuple)
+            {
+                TupleDeclaration *td = isAliasThisTuple(e2x);
+                if (!td)
+                    goto Lnomatch;
+
+                assert(exp->e1->type->ty == Ttuple);
+                TypeTuple *tt = (TypeTuple *)exp->e1->type;
+
+                Expression *e0 = NULL;
+                Expression *ev = extractSideEffect(sc, "__tup", &e0, e2x);
+
+                Expressions *iexps = new Expressions();
+                iexps->push(ev);
+
+                for (size_t u = 0; u < iexps->dim ; u++)
+                {
+            Lexpand:
+                    Expression *e = (*iexps)[u];
+
+                    Parameter *arg = Parameter::getNth(tt->arguments, u);
+                    //printf("[%d] iexps->dim = %d, ", u, iexps->dim);
+                    //printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars());
+                    //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
+
+                    if (!arg || !e->type->implicitConvTo(arg->type))
+                    {
+                        // expand initializer to tuple
+                        if (expandAliasThisTuples(iexps, u) != -1)
+                        {
+                            if (iexps->dim <= u)
+                                break;
+                            goto Lexpand;
+                        }
+                        goto Lnomatch;
+                    }
+                }
+                e2x = new TupleExp(e2x->loc, e0, iexps);
+                e2x = semantic(e2x, sc);
+                if (e2x->op == TOKerror)
+                {
+                    result = e2x;
+                    return;
+                }
+                // Do not need to overwrite exp->e2
+                goto Ltupleassign;
+            }
+        Lnomatch:
+            ;
+        }
+
+        /* Inside constructor, if this is the first assignment of object field,
+         * rewrite this to initializing the field.
+         */
+        if (exp->op == TOKassign && exp->e1->checkModifiable(sc) == 2)
+        {
+            //printf("[%s] change to init - %s\n", exp->loc.toChars(), toChars());
+            exp->op = TOKconstruct;
+
+            // Bugzilla 13515: set Index::modifiable flag for complex AA element initialization
+            if (exp->e1->op == TOKindex)
+            {
+                Expression *e1x = ((IndexExp *)exp->e1)->markSettingAAElem();
+                if (e1x->op == TOKerror)
+                {
+                    result = e1x;
+                    return;
+                }
+            }
+        }
+        else if (exp->op == TOKconstruct && exp->e1->op == TOKvar &&
+                 ((VarExp *)exp->e1)->var->storage_class & (STCout | STCref))
+        {
+            exp->memset |= referenceInit;
+        }
+
+        /* If it is an assignment from a 'foreign' type,
+         * check for operator overloading.
+         */
+        if (exp->memset & referenceInit)
+        {
+            // If this is an initialization of a reference,
+            // do nothing
+        }
+        else if (t1->ty == Tstruct)
+        {
+            Expression *e1x = exp->e1;
+            Expression *e2x = exp->e2;
+            StructDeclaration *sd = ((TypeStruct *)t1)->sym;
+
+            if (exp->op == TOKconstruct)
+            {
+                Type *t2 = e2x->type->toBasetype();
+                if (t2->ty == Tstruct && sd == ((TypeStruct *)t2)->sym)
+                {
+                    sd->size(exp->loc);
+                    if (sd->sizeok != SIZEOKdone)
+                        return setError();
+                    if (!sd->ctor)
+                        sd->ctor = sd->searchCtor();
+
+                    // Bugzilla 15661: Look for the form from last of comma chain.
+                    Expression *e2y = e2x;
+                    while (e2y->op == TOKcomma)
+                        e2y = ((CommaExp *)e2y)->e2;
+
+                    CallExp *ce = (e2y->op == TOKcall) ? (CallExp *)e2y : NULL;
+                    DotVarExp *dve = (ce && ce->e1->op == TOKdotvar)
+                        ? (DotVarExp *)ce->e1 : NULL;
+                    if (sd->ctor && ce && dve && dve->var->isCtorDeclaration() &&
+                        e2y->type->implicitConvTo(t1))
+                    {
+                        /* Look for form of constructor call which is:
+                         *    __ctmp.ctor(arguments...)
+                         */
+
+                        /* Before calling the constructor, initialize
+                         * variable with a bit copy of the default
+                         * initializer
+                         */
+                        AssignExp *ae = exp;
+                        if (sd->zeroInit == 1 && !sd->isNested())
+                        {
+                            // Bugzilla 14606: Always use BlitExp for the special expression: (struct = 0)
+                            ae = new BlitExp(ae->loc, ae->e1, new IntegerExp(exp->loc, 0, Type::tint32));
+                        }
+                        else
+                        {
+                            // Keep ae->op == TOKconstruct
+                            ae->e2 = sd->isNested() ? t1->defaultInitLiteral(exp->loc) : t1->defaultInit(exp->loc);
+                        }
+                        ae->type = e1x->type;
+
+                        /* Replace __ctmp being constructed with e1.
+                         * We need to copy constructor call expression,
+                         * because it may be used in other place.
+                         */
+                        DotVarExp *dvx = (DotVarExp *)dve->copy();
+                        dvx->e1 = e1x;
+                        CallExp *cx = (CallExp *)ce->copy();
+                        cx->e1 = dvx;
+
+                        Expression *e0;
+                        Expression::extractLast(e2x, &e0);
+
+                        Expression *e = Expression::combine(ae, cx);
+                        e = Expression::combine(e0, e);
+                        e = semantic(e, sc);
+                        result = e;
+                        return;
+                    }
+                    if (sd->postblit)
+                    {
+                        /* We have a copy constructor for this
+                        */
+                        if (e2x->op == TOKquestion)
+                        {
+                            /* Rewrite as:
+                             *  a ? e1 = b : e1 = c;
+                             */
+                            CondExp *econd = (CondExp *)e2x;
+                            Expression *ea1 = new ConstructExp(econd->e1->loc, e1x, econd->e1);
+                            Expression *ea2 = new ConstructExp(econd->e1->loc, e1x, econd->e2);
+                            Expression *e = new CondExp(exp->loc, econd->econd, ea1, ea2);
+                            result = semantic(e, sc);
+                            return;
+                        }
+
+                        if (e2x->isLvalue())
+                        {
+                            if (!e2x->type->implicitConvTo(e1x->type))
+                            {
+                                exp->error("conversion error from %s to %s", e2x->type->toChars(), e1x->type->toChars());
+                                return setError();
+                            }
+
+                            /* Rewrite as:
+                             *  (e1 = e2).postblit();
+                             *
+                             * Blit assignment e1 = e2 returns a reference to the original e1,
+                             * then call the postblit on it.
+                             */
+                            Expression *e = e1x->copy();
+                            e->type = e->type->mutableOf();
+                            e = new BlitExp(exp->loc, e, e2x);
+                            e = new DotVarExp(exp->loc, e, sd->postblit, false);
+                            e = new CallExp(exp->loc, e);
+                            result = semantic(e, sc);
+                            return;
+                        }
+                        else
+                        {
+                            /* The struct value returned from the function is transferred
+                             * so should not call the destructor on it.
+                             */
+                            e2x = valueNoDtor(e2x);
+                        }
+                    }
+                }
+                else if (!e2x->implicitConvTo(t1))
+                {
+                    sd->size(exp->loc);
+                    if (sd->sizeok != SIZEOKdone)
+                        return setError();
+                    if (!sd->ctor)
+                        sd->ctor = sd->searchCtor();
+
+                    if (sd->ctor)
+                    {
+                        /* Look for implicit constructor call
+                         * Rewrite as:
+                         *  e1 = init, e1.ctor(e2)
+                         */
+                        Expression *einit;
+                        einit = new BlitExp(exp->loc, e1x, e1x->type->defaultInit(exp->loc));
+                        einit->type = e1x->type;
+
+                        Expression *e;
+                        e = new DotIdExp(exp->loc, e1x, Id::ctor);
+                        e = new CallExp(exp->loc, e, e2x);
+                        e = new CommaExp(exp->loc, einit, e);
+                        e = semantic(e, sc);
+                        result = e;
+                        return;
+                    }
+                    if (search_function(sd, Id::call))
+                    {
+                        /* Look for static opCall
+                         * (See bugzilla 2702 for more discussion)
+                         * Rewrite as:
+                         *  e1 = typeof(e1).opCall(arguments)
+                         */
+                        e2x = typeDotIdExp(e2x->loc, e1x->type, Id::call);
+                        e2x = new CallExp(exp->loc, e2x, exp->e2);
+
+                        e2x = semantic(e2x, sc);
+                        e2x = resolveProperties(sc, e2x);
+                        if (e2x->op == TOKerror)
+                        {
+                            result = e2x;
+                            return;
+                        }
+                        if (e2x->checkValue())
+                            return setError();
+                    }
+                }
+                else    // Bugzilla 11355
+                {
+                    AggregateDeclaration *ad2 = isAggregate(e2x->type);
+                    if (ad2 && ad2->aliasthis && !(exp->att2 && e2x->type == exp->att2))
+                    {
+                        if (!exp->att2 && exp->e2->type->checkAliasThisRec())
+                            exp->att2 = exp->e2->type;
+
+                        /* Rewrite (e1 op e2) as:
+                         *      (e1 op e2.aliasthis)
+                         */
+                        exp->e2 = new DotIdExp(exp->e2->loc, exp->e2, ad2->aliasthis->ident);
+                        result = semantic(exp, sc);
+                        return;
+                    }
+                }
+            }
+            else if (exp->op == TOKassign)
+            {
+                if (e1x->op == TOKindex &&
+                    ((IndexExp *)e1x)->e1->type->toBasetype()->ty == Taarray)
+                {
+                    /*
+                     * Rewrite:
+                     *      aa[key] = e2;
+                     * as:
+                     *      ref __aatmp = aa;
+                     *      ref __aakey = key;
+                     *      ref __aaval = e2;
+                     *      (__aakey in __aatmp
+                     *          ? __aatmp[__aakey].opAssign(__aaval)
+                     *          : ConstructExp(__aatmp[__aakey], __aaval));
+                     */
+                    IndexExp *ie = (IndexExp *)e1x;
+                    Type *t2 = e2x->type->toBasetype();
+
+                    Expression *e0 = NULL;
+                    Expression *ea = extractSideEffect(sc, "__aatmp", &e0, ie->e1);
+                    Expression *ek = extractSideEffect(sc, "__aakey", &e0, ie->e2);
+                    Expression *ev = extractSideEffect(sc, "__aaval", &e0, e2x);
+
+                    AssignExp *ae = (AssignExp *)exp->copy();
+                    ae->e1 = new IndexExp(exp->loc, ea, ek);
+                    ae->e1 = semantic(ae->e1, sc);
+                    ae->e1 = ae->e1->optimize(WANTvalue);
+                    ae->e2 = ev;
+                    Expression *e = ae->op_overload(sc);
+                    if (e)
+                    {
+                        Expression *ey = NULL;
+                        if (t2->ty == Tstruct && sd == t2->toDsymbol(sc))
+                        {
+                            ey = ev;
+                        }
+                        else if (!ev->implicitConvTo(ie->type) && sd->ctor)
+                        {
+                            // Look for implicit constructor call
+                            // Rewrite as S().ctor(e2)
+                            ey = new StructLiteralExp(exp->loc, sd, NULL);
+                            ey = new DotIdExp(exp->loc, ey, Id::ctor);
+                            ey = new CallExp(exp->loc, ey, ev);
+                            ey = trySemantic(ey, sc);
+                        }
+                        if (ey)
+                        {
+                            Expression *ex;
+                            ex = new IndexExp(exp->loc, ea, ek);
+                            ex = semantic(ex, sc);
+                            ex = ex->optimize(WANTvalue);
+                            ex = ex->modifiableLvalue(sc, ex);  // allocate new slot
+                            ey = new ConstructExp(exp->loc, ex, ey);
+                            ey = semantic(ey, sc);
+                            if (ey->op == TOKerror)
+                            {
+                                result = ey;
+                                return;
+                            }
+                            ex = e;
+
+                            // Bugzilla 14144: The whole expression should have the common type
+                            // of opAssign() return and assigned AA entry.
+                            // Even if there's no common type, expression should be typed as void.
+                            Type *t = NULL;
+                            if (!typeMerge(sc, TOKquestion, &t, &ex, &ey))
+                            {
+                                ex = new CastExp(ex->loc, ex, Type::tvoid);
+                                ey = new CastExp(ey->loc, ey, Type::tvoid);
+                            }
+                            e = new CondExp(exp->loc, new InExp(exp->loc, ek, ea), ex, ey);
+                        }
+                        e = Expression::combine(e0, e);
+                        e = semantic(e, sc);
+                        result = e;
+                        return;
+                    }
+                }
+                else
+                {
+                    Expression *e = exp->op_overload(sc);
+                    if (e)
+                    {
+                        result = e;
+                        return;
+                    }
+                }
+            }
+            else
+                assert(exp->op == TOKblit);
+
+            exp->e1 = e1x;
+            exp->e2 = e2x;
+        }
+        else if (t1->ty == Tclass)
+        {
+            // Disallow assignment operator overloads for same type
+            if (exp->op == TOKassign && !exp->e2->implicitConvTo(exp->e1->type))
+            {
+                Expression *e = exp->op_overload(sc);
+                if (e)
+                {
+                    result = e;
+                    return;
+                }
+            }
+        }
+        else if (t1->ty == Tsarray)
+        {
+            // SliceExp cannot have static array type without context inference.
+            assert(exp->e1->op != TOKslice);
+
+            Expression *e1x = exp->e1;
+            Expression *e2x = exp->e2;
+
+            if (e2x->implicitConvTo(e1x->type))
+            {
+                if (exp->op != TOKblit &&
+                    (e2x->op == TOKslice && ((UnaExp *)e2x)->e1->isLvalue() ||
+                     e2x->op == TOKcast  && ((UnaExp *)e2x)->e1->isLvalue() ||
+                     e2x->op != TOKslice && e2x->isLvalue()))
+                {
+                    if (e1x->checkPostblit(sc, t1))
+                        return setError();
+                }
+
+                // e2 matches to t1 because of the implicit length match, so
+                if (isUnaArrayOp(e2x->op) || isBinArrayOp(e2x->op))
+                {
+                    // convert e1 to e1[]
+                    // e.g. e1[] = a[] + b[];
+                    e1x = new SliceExp(e1x->loc, e1x, NULL, NULL);
+                    e1x = semantic(e1x, sc);
+                }
+                else
+                {
+                    // convert e2 to t1 later
+                    // e.g. e1 = [1, 2, 3];
+                }
+            }
+            else
+            {
+                if (e2x->implicitConvTo(t1->nextOf()->arrayOf()) > MATCHnomatch)
+                {
+                    uinteger_t dim1 = ((TypeSArray *)t1)->dim->toInteger();
+                    uinteger_t dim2 = dim1;
+                    if (e2x->op == TOKarrayliteral)
+                    {
+                        ArrayLiteralExp *ale = (ArrayLiteralExp *)e2x;
+                        dim2 = ale->elements ? ale->elements->dim : 0;
+                    }
+                    else if (e2x->op == TOKslice)
+                    {
+                        Type *tx = toStaticArrayType((SliceExp *)e2x);
+                        if (tx)
+                            dim2 = ((TypeSArray *)tx)->dim->toInteger();
+                    }
+                    if (dim1 != dim2)
+                    {
+                        exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
+                        return setError();
+                    }
+                }
+
+                // May be block or element-wise assignment, so
+                // convert e1 to e1[]
+                if (exp->op != TOKassign)
+                {
+                    // If multidimensional static array, treat as one large array
+                    dinteger_t dim = ((TypeSArray *)t1)->dim->toInteger();
+                    Type *t = t1;
+                    while (1)
+                    {
+                        t = t->nextOf()->toBasetype();
+                        if (t->ty != Tsarray)
+                            break;
+                        dim *= ((TypeSArray *)t)->dim->toInteger();
+                        e1x->type = t->nextOf()->sarrayOf(dim);
+                    }
+                }
+                e1x = new SliceExp(e1x->loc, e1x, NULL, NULL);
+                e1x = semantic(e1x, sc);
+            }
+            if (e1x->op == TOKerror)
+            {
+                result = e1x;
+                return;
+            }
+            if (e2x->op == TOKerror)
+            {
+                result = e2x;
+                return;
+            }
+
+            exp->e1 = e1x;
+            exp->e2 = e2x;
+            t1 = e1x->type->toBasetype();
+        }
+
+        /* Check the mutability of e1.
+        */
+        if (exp->e1->op == TOKarraylength)
+        {
+            // e1 is not an lvalue, but we let code generator handle it
+            ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1;
+
+            Expression *ale1x = ale->e1;
+            ale1x = ale1x->modifiableLvalue(sc, exp->e1);
+            if (ale1x->op == TOKerror)
+            {
+                result = ale1x;
+                return;
+            }
+            ale->e1 = ale1x;
+
+            Type *tn = ale->e1->type->toBasetype()->nextOf();
+            checkDefCtor(ale->loc, tn);
+            semanticTypeInfo(sc, tn);
+        }
+        else if (exp->e1->op == TOKslice)
+        {
+            Type *tn = exp->e1->type->nextOf();
+            if (exp->op == TOKassign && !tn->isMutable())
+            {
+                exp->error("slice %s is not mutable", exp->e1->toChars());
+                return setError();
+            }
+
+            // For conditional operator, both branches need conversion.
+            SliceExp *se = (SliceExp *)exp->e1;
+            while (se->e1->op == TOKslice)
+                se = (SliceExp *)se->e1;
+            if (se->e1->op == TOKquestion &&
+                se->e1->type->toBasetype()->ty == Tsarray)
+            {
+                se->e1 = se->e1->modifiableLvalue(sc, exp->e1);
+                if (se->e1->op == TOKerror)
+                {
+                    result = se->e1;
+                    return;
+                }
+            }
+        }
+        else
+        {
+            Expression *e1x = exp->e1;
+
+            // Try to do a decent error message with the expression
+            // before it got constant folded
+            if (e1x->op != TOKvar)
+                e1x = e1x->optimize(WANTvalue);
+
+            if (exp->op == TOKassign)
+                e1x = e1x->modifiableLvalue(sc, e1old);
+
+            if (e1x->op == TOKerror)
+            {
+                result = e1x;
+                return;
+            }
+            exp->e1 = e1x;
+        }
+
+        /* Tweak e2 based on the type of e1.
+        */
+        Expression *e2x = exp->e2;
+        Type *t2 = e2x->type->toBasetype();
+
+        // If it is a array, get the element type. Note that it may be
+        // multi-dimensional.
+        Type *telem = t1;
+        while (telem->ty == Tarray)
+            telem = telem->nextOf();
+
+        if (exp->e1->op == TOKslice &&
+            t1->nextOf() && (telem->ty != Tvoid || e2x->op == TOKnull) &&
+            e2x->implicitConvTo(t1->nextOf())
+           )
+        {
+            // Check for block assignment. If it is of type void[], void[][], etc,
+            // '= null' is the only allowable block assignment (Bug 7493)
+            // memset
+            exp->memset |= blockAssign;  // make it easy for back end to tell what this is
+            e2x = e2x->implicitCastTo(sc, t1->nextOf());
+            if (exp->op != TOKblit && e2x->isLvalue() &&
+                exp->e1->checkPostblit(sc, t1->nextOf()))
+                return setError();
+        }
+        else if (exp->e1->op == TOKslice &&
+                 (t2->ty == Tarray || t2->ty == Tsarray) &&
+                 t2->nextOf()->implicitConvTo(t1->nextOf()))
+        {
+            // Check element-wise assignment.
+
+            /* If assigned elements number is known at compile time,
+             * check the mismatch.
+             */
+            SliceExp *se1 = (SliceExp *)exp->e1;
+            TypeSArray *tsa1 = (TypeSArray *)toStaticArrayType(se1);
+            TypeSArray *tsa2 = NULL;
+            if (e2x->op == TOKarrayliteral)
+                tsa2 = (TypeSArray *)t2->nextOf()->sarrayOf(((ArrayLiteralExp *)e2x)->elements->dim);
+            else if (e2x->op == TOKslice)
+                tsa2 = (TypeSArray *)toStaticArrayType((SliceExp *)e2x);
+            else if (t2->ty == Tsarray)
+                tsa2 = (TypeSArray *)t2;
+            if (tsa1 && tsa2)
+            {
+                uinteger_t dim1 = tsa1->dim->toInteger();
+                uinteger_t dim2 = tsa2->dim->toInteger();
+                if (dim1 != dim2)
+                {
+                    exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
+                    return setError();
+                }
+            }
+
+            if (exp->op != TOKblit &&
+                (e2x->op == TOKslice && ((UnaExp *)e2x)->e1->isLvalue() ||
+                 e2x->op == TOKcast  && ((UnaExp *)e2x)->e1->isLvalue() ||
+                 e2x->op != TOKslice && e2x->isLvalue()))
+            {
+                if (exp->e1->checkPostblit(sc, t1->nextOf()))
+                    return setError();
+            }
+
+            if (0 && global.params.warnings && !global.gag && exp->op == TOKassign &&
+                e2x->op != TOKslice && e2x->op != TOKassign &&
+                e2x->op != TOKarrayliteral && e2x->op != TOKstring &&
+                !(e2x->op == TOKadd || e2x->op == TOKmin ||
+                  e2x->op == TOKmul || e2x->op == TOKdiv ||
+                  e2x->op == TOKmod || e2x->op == TOKxor ||
+                  e2x->op == TOKand || e2x->op == TOKor  ||
+                  e2x->op == TOKpow ||
+                  e2x->op == TOKtilde || e2x->op == TOKneg))
+            {
+                const char* e1str = exp->e1->toChars();
+                const char* e2str = e2x->toChars();
+                exp->warning("explicit element-wise assignment %s = (%s)[] is better than %s = %s",
+                    e1str, e2str, e1str, e2str);
+            }
+
+            Type *t2n = t2->nextOf();
+            Type *t1n = t1->nextOf();
+            int offset;
+            if (t2n->equivalent(t1n) ||
+                t1n->isBaseOf(t2n, &offset) && offset == 0)
+            {
+                /* Allow copy of distinct qualifier elements.
+                 * eg.
+                 *  char[] dst;  const(char)[] src;
+                 *  dst[] = src;
+                 *
+                 *  class C {}   class D : C {}
+                 *  C[2] ca;  D[] da;
+                 *  ca[] = da;
+                 */
+                if (isArrayOpValid(e2x))
+                {
+                    // Don't add CastExp to keep AST for array operations
+                    e2x = e2x->copy();
+                    e2x->type = exp->e1->type->constOf();
+                }
+                else
+                    e2x = e2x->castTo(sc, exp->e1->type->constOf());
+            }
+            else
+            {
+                /* Bugzilla 15778: A string literal has an array type of immutable
+                 * elements by default, and normally it cannot be convertible to
+                 * array type of mutable elements. But for element-wise assignment,
+                 * elements need to be const at best. So we should give a chance
+                 * to change code unit size for polysemous string literal.
+                 */
+                if (e2x->op == TOKstring)
+                    e2x = e2x->implicitCastTo(sc, exp->e1->type->constOf());
+                else
+                    e2x = e2x->implicitCastTo(sc, exp->e1->type);
+            }
+        }
+        else
+        {
+            if (0 && global.params.warnings && !global.gag && exp->op == TOKassign &&
+                t1->ty == Tarray && t2->ty == Tsarray &&
+                e2x->op != TOKslice &&
+                t2->implicitConvTo(t1))
+            {   // Disallow ar[] = sa (Converted to ar[] = sa[])
+                // Disallow da   = sa (Converted to da   = sa[])
+                const char* e1str = exp->e1->toChars();
+                const char* e2str = e2x->toChars();
+                const char* atypestr = exp->e1->op == TOKslice ? "element-wise" : "slice";
+                exp->warning("explicit %s assignment %s = (%s)[] is better than %s = %s",
+                    atypestr, e1str, e2str, e1str, e2str);
+            }
+            if (exp->op == TOKblit)
+                e2x = e2x->castTo(sc, exp->e1->type);
+            else
+                e2x = e2x->implicitCastTo(sc, exp->e1->type);
+        }
+        if (e2x->op == TOKerror)
+        {
+            result = e2x;
+            return;
+        }
+        exp->e2 = e2x;
+        t2 = exp->e2->type->toBasetype();
+
+        /* Look for array operations
+        */
+        if ((t2->ty == Tarray || t2->ty == Tsarray) && isArrayOpValid(exp->e2))
+        {
+            // Look for valid array operations
+            if (!(exp->memset & blockAssign) && exp->e1->op == TOKslice &&
+                (isUnaArrayOp(exp->e2->op) || isBinArrayOp(exp->e2->op)))
+            {
+                exp->type = exp->e1->type;
+                if (exp->op == TOKconstruct) // Bugzilla 10282: tweak mutability of e1 element
+                    exp->e1->type = exp->e1->type->nextOf()->mutableOf()->arrayOf();
+                result = arrayOp(exp, sc);
+                return;
+            }
+
+            // Drop invalid array operations in e2
+            //  d = a[] + b[], d = (a[] + b[])[0..2], etc
+            if (checkNonAssignmentArrayOp(exp->e2, !(exp->memset & blockAssign) && exp->op == TOKassign))
+                return setError();
+
+            // Remains valid array assignments
+            //  d = d[], d = [1,2,3], etc
+        }
+
+        /* Don't allow assignment to classes that were allocated on the stack with:
+         *      scope Class c = new Class();
+         */
+
+        if (exp->e1->op == TOKvar && exp->op == TOKassign)
+        {
+            VarExp *ve = (VarExp *)exp->e1;
+            VarDeclaration *vd = ve->var->isVarDeclaration();
+            if (vd && (vd->onstack || vd->mynew))
+            {
+                assert(t1->ty == Tclass);
+                exp->error("cannot rebind scope variables");
+            }
+        }
+        if (exp->e1->op == TOKvar && ((VarExp *)exp->e1)->var->ident == Id::ctfe)
+        {
+            exp->error("cannot modify compiler-generated variable __ctfe");
+        }
+
+        exp->type = exp->e1->type;
+        assert(exp->type);
+        Expression *res = exp->op == TOKassign ? exp->reorderSettingAAElem(sc) : exp;
+        checkAssignEscape(sc, res, false);
+        result = res;
+    }
+
+    void visit(CatAssignExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        //printf("CatAssignExp::semantic() %s\n", toChars());
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (exp->e1->op == TOKslice)
+        {
+            SliceExp *se = (SliceExp *)exp->e1;
+            if (se->e1->type->toBasetype()->ty == Tsarray)
+            {
+                exp->error("cannot append to static array %s", se->e1->type->toChars());
+                return setError();
+            }
+        }
+
+        exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
+        if (exp->e1->op == TOKerror)
+        {
+            result = exp->e1;
+            return;
+        }
+        if (exp->e2->op == TOKerror)
+        {
+            result = exp->e2;
+            return;
+        }
+
+        if (checkNonAssignmentArrayOp(exp->e2))
+            return setError();
+
+        Type *tb1 = exp->e1->type->toBasetype();
+        Type *tb1next = tb1->nextOf();
+        Type *tb2 = exp->e2->type->toBasetype();
+
+        if ((tb1->ty == Tarray) &&
+            (tb2->ty == Tarray || tb2->ty == Tsarray) &&
+            (exp->e2->implicitConvTo(exp->e1->type)
+             || (tb2->nextOf()->implicitConvTo(tb1next) &&
+                 (tb2->nextOf()->size(Loc()) == tb1next->size(Loc())))
+            )
+           )
+        {
+            // Append array
+            if (exp->e1->checkPostblit(sc, tb1next))
+                return setError();
+            exp->e2 = exp->e2->castTo(sc, exp->e1->type);
+        }
+        else if ((tb1->ty == Tarray) &&
+                 exp->e2->implicitConvTo(tb1next)
+                )
+        {
+            // Append element
+            if (exp->e2->checkPostblit(sc, tb2))
+                return setError();
+            exp->e2 = exp->e2->castTo(sc, tb1next);
+            exp->e2 = doCopyOrMove(sc, exp->e2);
+        }
+        else if (tb1->ty == Tarray &&
+                 (tb1next->ty == Tchar || tb1next->ty == Twchar) &&
+                 exp->e2->type->ty != tb1next->ty &&
+                 exp->e2->implicitConvTo(Type::tdchar)
+                )
+        {   // Append dchar to char[] or wchar[]
+            exp->e2 = exp->e2->castTo(sc, Type::tdchar);
+
+            /* Do not allow appending wchar to char[] because if wchar happens
+             * to be a surrogate pair, nothing good can result.
+             */
+        }
+        else
+        {
+            exp->error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars());
+            return setError();
+        }
+        if (exp->e2->checkValue())
+            return setError();
+
+        exp->type = exp->e1->type;
+        result = exp->reorderSettingAAElem(sc);
+    }
+
+    void visit(PowAssignExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (exp->e1->checkReadModifyWrite(exp->op, exp->e2))
+            return setError();
+
+        assert(exp->e1->type && exp->e2->type);
+        if (exp->e1->op == TOKslice || exp->e1->type->ty == Tarray || exp->e1->type->ty == Tsarray)
+        {
+            // T[] ^^= ...
+            if (exp->e2->implicitConvTo(exp->e1->type->nextOf()))
+            {
+                // T[] ^^= T
+                exp->e2 = exp->e2->castTo(sc, exp->e1->type->nextOf());
+            }
+            else if (Expression *ex = typeCombine(exp, sc))
+            {
+                result = ex;
+                return;
+            }
+
+            // Check element types are arithmetic
+            Type *tb1 = exp->e1->type->nextOf()->toBasetype();
+            Type *tb2 = exp->e2->type->toBasetype();
+            if (tb2->ty == Tarray || tb2->ty == Tsarray)
+                tb2 = tb2->nextOf()->toBasetype();
+
+            if ( (tb1->isintegral() || tb1->isfloating()) &&
+                 (tb2->isintegral() || tb2->isfloating()))
+            {
+                exp->type = exp->e1->type;
+                result = arrayOp(exp, sc);
+                return;
+            }
+        }
+        else
+        {
+            exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
+        }
+
+        if ((exp->e1->type->isintegral() || exp->e1->type->isfloating()) &&
+            (exp->e2->type->isintegral() || exp->e2->type->isfloating()))
+        {
+            Expression *e0 = NULL;
+            e = exp->reorderSettingAAElem(sc);
+            e = Expression::extractLast(e, &e0);
+            assert(e == exp);
+
+            if (exp->e1->op == TOKvar)
+            {
+                // Rewrite: e1 = e1 ^^ e2
+                e = new PowExp(exp->loc, exp->e1->syntaxCopy(), exp->e2);
+                e = new AssignExp(exp->loc, exp->e1, e);
+            }
+            else
+            {
+                // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
+                VarDeclaration *v = copyToTemp(STCref, "__powtmp", exp->e1);
+                Expression *de = new DeclarationExp(exp->e1->loc, v);
+                VarExp *ve = new VarExp(exp->e1->loc, v);
+                e = new PowExp(exp->loc, ve, exp->e2);
+                e = new AssignExp(exp->loc, new VarExp(exp->e1->loc, v), e);
+                e = new CommaExp(exp->loc, de, e);
+            }
+            e = Expression::combine(e0, e);
+            e = semantic(e, sc);
+            result = e;
+            return;
+        }
+        result = exp->incompatibleTypes();
+    }
+
+    void visit(AddExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("AddExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        Type *tb1 = exp->e1->type->toBasetype();
+        Type *tb2 = exp->e2->type->toBasetype();
+
+        bool err = false;
+        if (tb1->ty == Tdelegate ||
+            tb1->ty == Tpointer && tb1->nextOf()->ty == Tfunction)
+        {
+            err |= exp->e1->checkArithmetic();
+        }
+        if (tb2->ty == Tdelegate ||
+            tb2->ty == Tpointer && tb2->nextOf()->ty == Tfunction)
+        {
+            err |= exp->e2->checkArithmetic();
+        }
+        if (err)
+            return setError();
+
+        if (tb1->ty == Tpointer && exp->e2->type->isintegral() ||
+            tb2->ty == Tpointer && exp->e1->type->isintegral())
+        {
+            result = scaleFactor(exp, sc);
+            return;
+        }
+
+        if (tb1->ty == Tpointer && tb2->ty == Tpointer)
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        Type *tb = exp->type->toBasetype();
+        if (tb->ty == Tarray || tb->ty == Tsarray)
+        {
+            if (!isArrayOpValid(exp))
+            {
+                exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+                return setError();
+            }
+            result = exp;
+            return;
+        }
+
+        tb1 = exp->e1->type->toBasetype();
+        if (!Target::isVectorOpSupported(tb1, exp->op, tb2))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        if ((tb1->isreal() && exp->e2->type->isimaginary()) ||
+            (tb1->isimaginary() && exp->e2->type->isreal()))
+        {
+            switch (exp->type->toBasetype()->ty)
+            {
+                case Tfloat32:
+                case Timaginary32:
+                    exp->type = Type::tcomplex32;
+                    break;
+
+                case Tfloat64:
+                case Timaginary64:
+                    exp->type = Type::tcomplex64;
+                    break;
+
+                case Tfloat80:
+                case Timaginary80:
+                    exp->type = Type::tcomplex80;
+                    break;
+
+                default:
+                    assert(0);
+            }
+        }
+        result = exp;
+    }
+
+    void visit(MinExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("MinExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        Type *t1 = exp->e1->type->toBasetype();
+        Type *t2 = exp->e2->type->toBasetype();
+
+        bool err = false;
+        if (t1->ty == Tdelegate ||
+            t1->ty == Tpointer && t1->nextOf()->ty == Tfunction)
+        {
+            err |= exp->e1->checkArithmetic();
+        }
+        if (t2->ty == Tdelegate ||
+            t2->ty == Tpointer && t2->nextOf()->ty == Tfunction)
+        {
+            err |= exp->e2->checkArithmetic();
+        }
+        if (err)
+            return setError();
+
+        if (t1->ty == Tpointer)
+        {
+            if (t2->ty == Tpointer)
+            {
+                // Need to divide the result by the stride
+                // Replace (ptr - ptr) with (ptr - ptr) / stride
+                d_int64 stride;
+
+                // make sure pointer types are compatible
+                if (Expression *ex = typeCombine(exp, sc))
+                {
+                    result = ex;
+                    return;
+                }
+
+                exp->type = Type::tptrdiff_t;
+                stride = t2->nextOf()->size();
+                if (stride == 0)
+                {
+                    e = new IntegerExp(exp->loc, 0, Type::tptrdiff_t);
+                }
+                else
+                {
+                    e = new DivExp(exp->loc, exp, new IntegerExp(Loc(), stride, Type::tptrdiff_t));
+                    e->type = Type::tptrdiff_t;
+                }
+            }
+            else if (t2->isintegral())
+                e = scaleFactor(exp, sc);
+            else
+            {
+                exp->error("can't subtract %s from pointer", t2->toChars());
+                e = new ErrorExp();
+            }
+            result = e;
+            return;
+        }
+        if (t2->ty == Tpointer)
+        {
+            exp->type = exp->e2->type;
+            exp->error("can't subtract pointer from %s", exp->e1->type->toChars());
+            return setError();
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        Type *tb = exp->type->toBasetype();
+        if (tb->ty == Tarray || tb->ty == Tsarray)
+        {
+            if (!isArrayOpValid(exp))
+            {
+                exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+                return setError();
+            }
+            result = exp;
+            return;
+        }
+
+        t1 = exp->e1->type->toBasetype();
+        t2 = exp->e2->type->toBasetype();
+        if (!Target::isVectorOpSupported(t1, exp->op, t2))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        if ((t1->isreal() && t2->isimaginary()) ||
+            (t1->isimaginary() && t2->isreal()))
+        {
+            switch (exp->type->ty)
+            {
+                case Tfloat32:
+                case Timaginary32:
+                    exp->type = Type::tcomplex32;
+                    break;
+
+                case Tfloat64:
+                case Timaginary64:
+                    exp->type = Type::tcomplex64;
+                    break;
+
+                case Tfloat80:
+                case Timaginary80:
+                    exp->type = Type::tcomplex80;
+                    break;
+
+                default:
+                    assert(0);
+            }
+        }
+        result = exp;
+    }
+
+    void visit(CatExp *exp)
+    {
+        //printf("CatExp::semantic() %s\n", exp->toChars());
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        Type *tb1 = exp->e1->type->toBasetype();
+        Type *tb2 = exp->e2->type->toBasetype();
+
+        bool f1 = checkNonAssignmentArrayOp(exp->e1);
+        bool f2 = checkNonAssignmentArrayOp(exp->e2);
+        if (f1 || f2)
+            return setError();
+
+        /* BUG: Should handle things like:
+         *      char c;
+         *      c ~ ' '
+         *      ' ' ~ c;
+         */
+
+#if 0
+        exp->e1->type->print();
+        exp->e2->type->print();
+#endif
+        Type *tb1next = tb1->nextOf();
+        Type *tb2next = tb2->nextOf();
+
+        // Check for: array ~ array
+        if (tb1next && tb2next &&
+            (tb1next->implicitConvTo(tb2next) >= MATCHconst ||
+             tb2next->implicitConvTo(tb1next) >= MATCHconst ||
+             exp->e1->op == TOKarrayliteral && exp->e1->implicitConvTo(tb2) ||
+             exp->e2->op == TOKarrayliteral && exp->e2->implicitConvTo(tb1)
+            )
+           )
+        {
+            /* Bugzilla 9248: Here to avoid the case of:
+             *    void*[] a = [cast(void*)1];
+             *    void*[] b = [cast(void*)2];
+             *    a ~ b;
+             * becoming:
+             *    a ~ [cast(void*)b];
+             */
+
+            /* Bugzilla 14682: Also to avoid the case of:
+             *    int[][] a;
+             *    a ~ [];
+             * becoming:
+             *    a ~ cast(int[])[];
+             */
+            goto Lpeer;
+        }
+
+        // Check for: array ~ element
+        if ((tb1->ty == Tsarray || tb1->ty == Tarray) && tb2->ty != Tvoid)
+        {
+            if (exp->e1->op == TOKarrayliteral && exp->e1->implicitConvTo(tb2->arrayOf()))
+            {
+                if (exp->e2->checkPostblit(sc, tb2))
+                    return setError();
+                exp->e1 = exp->e1->implicitCastTo(sc, tb2->arrayOf());
+                exp->type = tb2->arrayOf();
+                goto L2elem;
+            }
+            if (exp->e2->implicitConvTo(tb1next) >= MATCHconvert)
+            {
+                if (exp->e2->checkPostblit(sc, tb2))
+                    return setError();
+                exp->e2 = exp->e2->implicitCastTo(sc, tb1next);
+                exp->type = tb1next->arrayOf();
+            L2elem:
+                if (tb2->ty == Tarray || tb2->ty == Tsarray)
+                {
+                    // Make e2 into [e2]
+                    exp->e2 = new ArrayLiteralExp(exp->e2->loc, exp->e2);
+                    exp->e2->type = exp->type;
+                }
+                result = exp;
+                return;
+            }
+        }
+        // Check for: element ~ array
+        if ((tb2->ty == Tsarray || tb2->ty == Tarray) && tb1->ty != Tvoid)
+        {
+            if (exp->e2->op == TOKarrayliteral &&
+                exp->e2->implicitConvTo(tb1->arrayOf()))
+            {
+                if (exp->e1->checkPostblit(sc, tb1))
+                    return setError();
+                exp->e2 = exp->e2->implicitCastTo(sc, tb1->arrayOf());
+                exp->type = tb1->arrayOf();
+                goto L1elem;
+            }
+            if (exp->e1->implicitConvTo(tb2next) >= MATCHconvert)
+            {
+                if (exp->e1->checkPostblit(sc, tb1))
+                    return setError();
+                exp->e1 = exp->e1->implicitCastTo(sc, tb2next);
+                exp->type = tb2next->arrayOf();
+            L1elem:
+                if (tb1->ty == Tarray || tb1->ty == Tsarray)
+                {
+                    // Make e1 into [e1]
+                    exp->e1 = new ArrayLiteralExp(exp->e1->loc, exp->e1);
+                    exp->e1->type = exp->type;
+                }
+                result = exp;
+                return;
+            }
+        }
+
+    Lpeer:
+        if ((tb1->ty == Tsarray || tb1->ty == Tarray) &&
+            (tb2->ty == Tsarray || tb2->ty == Tarray) &&
+            (tb1next->mod || tb2next->mod) &&
+            (tb1next->mod != tb2next->mod)
+           )
+        {
+            Type *t1 = tb1next->mutableOf()->constOf()->arrayOf();
+            Type *t2 = tb2next->mutableOf()->constOf()->arrayOf();
+            if (exp->e1->op == TOKstring && !((StringExp *)exp->e1)->committed)
+                exp->e1->type = t1;
+            else
+                exp->e1 = exp->e1->castTo(sc, t1);
+            if (exp->e2->op == TOKstring && !((StringExp *)exp->e2)->committed)
+                exp->e2->type = t2;
+            else
+                exp->e2 = exp->e2->castTo(sc, t2);
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        exp->type = exp->type->toHeadMutable();
+
+        Type *tb = exp->type->toBasetype();
+        if (tb->ty == Tsarray)
+            exp->type = tb->nextOf()->arrayOf();
+        if (exp->type->ty == Tarray && tb1next && tb2next &&
+            tb1next->mod != tb2next->mod)
+        {
+            exp->type = exp->type->nextOf()->toHeadMutable()->arrayOf();
+        }
+        if (Type *tbn = tb->nextOf())
+        {
+            if (exp->checkPostblit(sc, tbn))
+                return setError();
+        }
+#if 0
+        exp->e1->type->print();
+        exp->e2->type->print();
+        exp->type->print();
+        print();
+#endif
+        Type *t1 = exp->e1->type->toBasetype();
+        Type *t2 = exp->e2->type->toBasetype();
+        if (exp->e1->op == TOKstring && exp->e2->op == TOKstring)
+        {
+            e = exp->optimize(WANTvalue);
+        }
+        else if ((t1->ty == Tarray || t1->ty == Tsarray) &&
+                 (t2->ty == Tarray || t2->ty == Tsarray))
+        {
+            e = exp;
+        }
+        else
+        {
+            //printf("(%s) ~ (%s)\n", exp->e1->toChars(), exp->e2->toChars());
+            result = exp->incompatibleTypes();
+            return;
+        }
+
+        e->type = e->type->semantic(exp->loc, sc);
+        result = e;
+    }
+
+    void visit(MulExp *exp)
+    {
+#if 0
+        printf("MulExp::semantic() %s\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        Type *tb = exp->type->toBasetype();
+        if (tb->ty == Tarray || tb->ty == Tsarray)
+        {
+            if (!isArrayOpValid(exp))
+            {
+                exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+                return setError();
+            }
+            result = exp;
+            return;
+        }
+
+        if (exp->checkArithmeticBin())
+            return setError();
+
+        if (exp->type->isfloating())
+        {
+            Type *t1 = exp->e1->type;
+            Type *t2 = exp->e2->type;
+
+            if (t1->isreal())
+            {
+                exp->type = t2;
+            }
+            else if (t2->isreal())
+            {
+                exp->type = t1;
+            }
+            else if (t1->isimaginary())
+            {
+                if (t2->isimaginary())
+                {
+
+                    switch (t1->toBasetype()->ty)
+                    {
+                        case Timaginary32:
+                            exp->type = Type::tfloat32;
+                            break;
+
+                        case Timaginary64:
+                            exp->type = Type::tfloat64;
+                            break;
+
+                        case Timaginary80:
+                            exp->type = Type::tfloat80;
+                            break;
+
+                        default:
+                            assert(0);
+                    }
+
+                    // iy * iv = -yv
+                    exp->e1->type = exp->type;
+                    exp->e2->type = exp->type;
+                    e = new NegExp(exp->loc, exp);
+                    e = semantic(e, sc);
+                    result = e;
+                    return;
+                }
+                else
+                    exp->type = t2;      // t2 is complex
+            }
+            else if (t2->isimaginary())
+            {
+                exp->type = t1;  // t1 is complex
+            }
+        }
+        else if (!Target::isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        result = exp;
+    }
+
+    void visit(DivExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        Type *tb = exp->type->toBasetype();
+        if (tb->ty == Tarray || tb->ty == Tsarray)
+        {
+            if (!isArrayOpValid(exp))
+            {
+                exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+                return setError();
+            }
+            result = exp;
+            return;
+        }
+
+        if (exp->checkArithmeticBin())
+            return setError();
+
+        if (exp->type->isfloating())
+        {
+            Type *t1 = exp->e1->type;
+            Type *t2 = exp->e2->type;
+
+            if (t1->isreal())
+            {
+                exp->type = t2;
+                if (t2->isimaginary())
+                {
+                    // x/iv = i(-x/v)
+                    exp->e2->type = t1;
+                    e = new NegExp(exp->loc, exp);
+                    e = semantic(e, sc);
+                    result = e;
+                    return;
+                }
+            }
+            else if (t2->isreal())
+            {
+                exp->type = t1;
+            }
+            else if (t1->isimaginary())
+            {
+                if (t2->isimaginary())
+                {
+                    switch (t1->toBasetype()->ty)
+                    {
+                        case Timaginary32:
+                            exp->type = Type::tfloat32;
+                            break;
+
+                        case Timaginary64:
+                            exp->type = Type::tfloat64;
+                            break;
+
+                        case Timaginary80:
+                            exp->type = Type::tfloat80;
+                            break;
+
+                        default:
+                            assert(0);
+                    }
+                }
+                else
+                    exp->type = t2;      // t2 is complex
+            }
+            else if (t2->isimaginary())
+            {
+                exp->type = t1;  // t1 is complex
+            }
+        }
+        else if (!Target::isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        result = exp;
+    }
+
+    void visit(ModExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        Type *tb = exp->type->toBasetype();
+        if (tb->ty == Tarray || tb->ty == Tsarray)
+        {
+            if (!isArrayOpValid(exp))
+            {
+                exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+                return setError();
+            }
+            result = exp;
+            return;
+        }
+        if (!Target::isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+
+        if (exp->checkArithmeticBin())
+            return setError();
+
+        if (exp->type->isfloating())
+        {
+            exp->type = exp->e1->type;
+            if (exp->e2->type->iscomplex())
+            {
+                exp->error("cannot perform modulo complex arithmetic");
+                return setError();
+            }
+        }
+        result = exp;
+    }
+
+    Module *loadStdMath()
+    {
+        static Import *impStdMath = NULL;
+        if (!impStdMath)
+        {
+            Identifiers *a = new Identifiers();
+            a->push(Id::std);
+            Import *s = new Import(Loc(), a, Id::math, NULL, false);
+            s->load(NULL);
+            if (s->mod)
+            {
+                s->mod->importAll(NULL);
+                s->mod->semantic(NULL);
+            }
+            impStdMath = s;
+        }
+        return impStdMath->mod;
+    }
+
+    void visit(PowExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        //printf("PowExp::semantic() %s\n", exp->toChars());
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        Type *tb = exp->type->toBasetype();
+        if (tb->ty == Tarray || tb->ty == Tsarray)
+        {
+            if (!isArrayOpValid(exp))
+            {
+                exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+                return setError();
+            }
+            result = exp;
+            return;
+        }
+
+        if (exp->checkArithmeticBin())
+            return setError();
+
+        if (!Target::isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+
+        // For built-in numeric types, there are several cases.
+        // TODO: backend support, especially for  e1 ^^ 2.
+
+        // First, attempt to fold the expression.
+        e = exp->optimize(WANTvalue);
+        if (e->op != TOKpow)
+        {
+            e = semantic(e, sc);
+            result = e;
+            return;
+        }
+
+        // Determine if we're raising to an integer power.
+        sinteger_t intpow = 0;
+        if (exp->e2->op == TOKint64 && ((sinteger_t)exp->e2->toInteger() == 2 || (sinteger_t)exp->e2->toInteger() == 3))
+            intpow = exp->e2->toInteger();
+        else if (exp->e2->op == TOKfloat64 && (exp->e2->toReal() == ldouble((sinteger_t)exp->e2->toReal())))
+            intpow = (sinteger_t)(exp->e2->toReal());
+
+        // Deal with x^^2, x^^3 immediately, since they are of practical importance.
+        if (intpow == 2 || intpow == 3)
+        {
+            // Replace x^^2 with (tmp = x, tmp*tmp)
+            // Replace x^^3 with (tmp = x, tmp*tmp*tmp)
+            VarDeclaration *tmp = copyToTemp(0, "__powtmp", exp->e1);
+            Expression *de = new DeclarationExp(exp->loc, tmp);
+            Expression *ve = new VarExp(exp->loc, tmp);
+
+            /* Note that we're reusing ve. This should be ok.
+            */
+            Expression *me = new MulExp(exp->loc, ve, ve);
+            if (intpow == 3)
+                me = new MulExp(exp->loc, me, ve);
+            e = new CommaExp(exp->loc, de, me);
+            e = semantic(e, sc);
+            result = e;
+            return;
+        }
+
+        Module *mmath = loadStdMath();
+        if (!mmath)
+        {
+            //exp->error("requires std.math for ^^ operators");
+            //fatal();
+
+            // Leave handling of PowExp to the backend, or throw
+            // an error gracefully if no backend support exists.
+            if (Expression *ex = typeCombine(exp, sc))
+            {
+                result = ex;
+                return;
+            }
+            result = exp;
+            return;
+        }
+        e = new ScopeExp(exp->loc, mmath);
+
+        if (exp->e2->op == TOKfloat64 && exp->e2->toReal() == CTFloat::half)
+        {
+            // Replace e1 ^^ 0.5 with .std.math.sqrt(x)
+            e = new CallExp(exp->loc, new DotIdExp(exp->loc, e, Id::_sqrt), exp->e1);
+        }
+        else
+        {
+            // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
+            e = new CallExp(exp->loc, new DotIdExp(exp->loc, e, Id::_pow), exp->e1, exp->e2);
+        }
+        e = semantic(e, sc);
+        result = e;
+    }
+
+    void visit(ShlExp *exp)
+    {
+        //printf("ShlExp::semantic(), type = %p\n", exp->type);
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (exp->checkIntegralBin())
+            return setError();
+        if (!Target::isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        exp->e1 = integralPromotions(exp->e1, sc);
+        if (exp->e2->type->toBasetype()->ty != Tvector)
+            exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
+
+        exp->type = exp->e1->type;
+        result = exp;
+    }
+
+    void visit(ShrExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (exp->checkIntegralBin())
+            return setError();
+        if (!Target::isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        exp->e1 = integralPromotions(exp->e1, sc);
+        if (exp->e2->type->toBasetype()->ty != Tvector)
+            exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
+
+        exp->type = exp->e1->type;
+        result = exp;
+    }
+
+    void visit(UshrExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (exp->checkIntegralBin())
+            return setError();
+        if (!Target::isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        exp->e1 = integralPromotions(exp->e1, sc);
+        if (exp->e2->type->toBasetype()->ty != Tvector)
+            exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
+
+        exp->type = exp->e1->type;
+        result = exp;
+    }
+
+    void visit(AndExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (exp->e1->type->toBasetype()->ty == Tbool &&
+            exp->e2->type->toBasetype()->ty == Tbool)
+        {
+            exp->type = exp->e1->type;
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        Type *tb = exp->type->toBasetype();
+        if (tb->ty == Tarray || tb->ty == Tsarray)
+        {
+            if (!isArrayOpValid(exp))
+            {
+                exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+                return setError();
+            }
+            result = exp;
+            return;
+        }
+
+        if (!Target::isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        if (exp->checkIntegralBin())
+            return setError();
+
+        result = exp;
+    }
+
+    void visit(OrExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (exp->e1->type->toBasetype()->ty == Tbool &&
+            exp->e2->type->toBasetype()->ty == Tbool)
+        {
+            exp->type = exp->e1->type;
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        Type *tb = exp->type->toBasetype();
+        if (tb->ty == Tarray || tb->ty == Tsarray)
+        {
+            if (!isArrayOpValid(exp))
+            {
+                exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+                return setError();
+            }
+            result = exp;
+            return;
+        }
+
+        if (!Target::isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        if (exp->checkIntegralBin())
+            return setError();
+
+        result = exp;
+    }
+
+    void visit(XorExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        if (exp->e1->type->toBasetype()->ty == Tbool &&
+            exp->e2->type->toBasetype()->ty == Tbool)
+        {
+            exp->type = exp->e1->type;
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        Type *tb = exp->type->toBasetype();
+        if (tb->ty == Tarray || tb->ty == Tsarray)
+        {
+            if (!isArrayOpValid(exp))
+            {
+                exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+                return setError();
+            }
+            result = exp;
+            return;
+        }
+
+        if (!Target::isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        if (exp->checkIntegralBin())
+            return setError();
+
+        result = exp;
+    }
+
+    void visit(OrOrExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        setNoderefOperands(exp);
+
+        // same as for AndAnd
+        Expression *e1x = semantic(exp->e1, sc);
+
+        // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+        if (e1x->op == TOKtype)
+            e1x = resolveAliasThis(sc, e1x);
+
+        e1x = resolveProperties(sc, e1x);
+        e1x = e1x->toBoolean(sc);
+        unsigned cs1 = sc->callSuper;
+
+        if (sc->flags & SCOPEcondition)
+        {
+            /* If in static if, don't evaluate e2 if we don't have to.
+            */
+            e1x = e1x->optimize(WANTvalue);
+            if (e1x->isBool(true))
+            {
+                result = new IntegerExp(exp->loc, 1, Type::tbool);
+                return;
+            }
+        }
+
+        Expression *e2x = semantic(exp->e2, sc);
+        sc->mergeCallSuper(exp->loc, cs1);
+
+        // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+        if (e2x->op == TOKtype)
+            e2x = resolveAliasThis(sc, e2x);
+
+        e2x = resolveProperties(sc, e2x);
+
+        bool f1 = checkNonAssignmentArrayOp(e1x);
+        bool f2 = checkNonAssignmentArrayOp(e2x);
+        if (f1 || f2)
+            return setError();
+
+        // Unless the right operand is 'void', the expression is converted to 'bool'.
+        if (e2x->type->ty != Tvoid)
+            e2x = e2x->toBoolean(sc);
+
+        if (e2x->op == TOKtype || e2x->op == TOKscope)
+        {
+            exp->error("%s is not an expression", exp->e2->toChars());
+            return setError();
+        }
+        if (e1x->op == TOKerror)
+        {
+            result = e1x;
+            return;
+        }
+        if (e2x->op == TOKerror)
+        {
+            result = e2x;
+            return;
+        }
+
+        // The result type is 'bool', unless the right operand has type 'void'.
+        if (e2x->type->ty == Tvoid)
+            exp->type = Type::tvoid;
+        else
+            exp->type = Type::tbool;
+
+        exp->e1 = e1x;
+        exp->e2 = e2x;
+        result = exp;
+    }
+
+    void visit(AndAndExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        setNoderefOperands(exp);
+
+        // same as for OrOr
+        Expression *e1x = semantic(exp->e1, sc);
+
+        // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+        if (e1x->op == TOKtype)
+            e1x = resolveAliasThis(sc, e1x);
+
+        e1x = resolveProperties(sc, e1x);
+        e1x = e1x->toBoolean(sc);
+        unsigned cs1 = sc->callSuper;
+
+        if (sc->flags & SCOPEcondition)
+        {
+            /* If in static if, don't evaluate e2 if we don't have to.
+            */
+            e1x = e1x->optimize(WANTvalue);
+            if (e1x->isBool(false))
+            {
+                result = new IntegerExp(exp->loc, 0, Type::tbool);
+                return;
+            }
+        }
+
+        Expression *e2x = semantic(exp->e2, sc);
+        sc->mergeCallSuper(exp->loc, cs1);
+
+        // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+        if (e2x->op == TOKtype)
+            e2x = resolveAliasThis(sc, e2x);
+
+        e2x = resolveProperties(sc, e2x);
+
+        bool f1 = checkNonAssignmentArrayOp(e1x);
+        bool f2 = checkNonAssignmentArrayOp(e2x);
+        if (f1 || f2)
+            return setError();
+
+        // Unless the right operand is 'void', the expression is converted to 'bool'.
+        if (e2x->type->ty != Tvoid)
+            e2x = e2x->toBoolean(sc);
+
+        if (e2x->op == TOKtype || e2x->op == TOKscope)
+        {
+            exp->error("%s is not an expression", exp->e2->toChars());
+            return setError();
+        }
+        if (e1x->op == TOKerror)
+        {
+            result = e1x;
+            return;
+        }
+        if (e2x->op == TOKerror)
+        {
+            result = e2x;
+            return;
+        }
+
+        // The result type is 'bool', unless the right operand has type 'void'.
+        if (e2x->type->ty == Tvoid)
+            exp->type = Type::tvoid;
+        else
+            exp->type = Type::tbool;
+
+        exp->e1 = e1x;
+        exp->e2 = e2x;
+        result = exp;
+    }
+
+    void visit(InExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        Type *t2b = exp->e2->type->toBasetype();
+        switch (t2b->ty)
+        {
+            case Taarray:
+                {
+                    TypeAArray *ta = (TypeAArray *)t2b;
+
+                    // Special handling for array keys
+                    if (!arrayTypeCompatible(exp->e1->loc, exp->e1->type, ta->index))
+                    {
+                        // Convert key to type of key
+                        exp->e1 = exp->e1->implicitCastTo(sc, ta->index);
+                    }
+
+                    semanticTypeInfo(sc, ta->index);
+
+                    // Return type is pointer to value
+                    exp->type = ta->nextOf()->pointerTo();
+                    break;
+                }
+
+            default:
+                exp->error("rvalue of in expression must be an associative array, not %s", exp->e2->type->toChars());
+            case Terror:
+                return setError();
+        }
+        result = exp;
+    }
+
+    void visit(RemoveExp *e)
+    {
+        if (Expression *ex = binSemantic(e, sc))
+        {
+            result = ex;
+            return;
+        }
+        result = e;
+    }
+
+    void visit(CmpExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("CmpExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        setNoderefOperands(exp);
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+        Type *t1 = exp->e1->type->toBasetype();
+        Type *t2 = exp->e2->type->toBasetype();
+        if (t1->ty == Tclass && exp->e2->op == TOKnull ||
+            t2->ty == Tclass && exp->e1->op == TOKnull)
+        {
+            exp->error("do not use null when comparing class types");
+            return setError();
+        }
+
+        Expression *e = exp->op_overload(sc);
+        if (e)
+        {
+            if (!e->type->isscalar() && e->type->equals(exp->e1->type))
+            {
+                exp->error("recursive opCmp expansion");
+                return setError();
+            }
+            if (e->op == TOKcall)
+            {
+                e = new CmpExp(exp->op, exp->loc, e, new IntegerExp(exp->loc, 0, Type::tint32));
+                e = semantic(e, sc);
+            }
+            result = e;
+            return;
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        bool f1 = checkNonAssignmentArrayOp(exp->e1);
+        bool f2 = checkNonAssignmentArrayOp(exp->e2);
+        if (f1 || f2)
+            return setError();
+
+        exp->type = Type::tbool;
+
+        // Special handling for array comparisons
+        t1 = exp->e1->type->toBasetype();
+        t2 = exp->e2->type->toBasetype();
+        if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
+            (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer))
+        {
+            Type *t1next = t1->nextOf();
+            Type *t2next = t2->nextOf();
+            if (t1next->implicitConvTo(t2next) < MATCHconst &&
+                t2next->implicitConvTo(t1next) < MATCHconst &&
+                (t1next->ty != Tvoid && t2next->ty != Tvoid))
+            {
+                exp->error("array comparison type mismatch, %s vs %s", t1next->toChars(), t2next->toChars());
+                return setError();
+            }
+            if ((t1->ty == Tarray || t1->ty == Tsarray) &&
+                (t2->ty == Tarray || t2->ty == Tsarray))
+            {
+                semanticTypeInfo(sc, t1->nextOf());
+            }
+        }
+        else if (t1->ty == Tstruct || t2->ty == Tstruct ||
+                 (t1->ty == Tclass && t2->ty == Tclass))
+        {
+            if (t2->ty == Tstruct)
+                exp->error("need member function opCmp() for %s %s to compare", t2->toDsymbol(sc)->kind(), t2->toChars());
+            else
+                exp->error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars());
+            return setError();
+        }
+        else if (t1->iscomplex() || t2->iscomplex())
+        {
+            exp->error("compare not defined for complex operands");
+            return setError();
+        }
+        else if (t1->ty == Taarray || t2->ty == Taarray)
+        {
+            exp->error("%s is not defined for associative arrays", Token::toChars(exp->op));
+            return setError();
+        }
+        else if (!Target::isVectorOpSupported(t1, exp->op, t2))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+        else
+        {
+            bool r1 = exp->e1->checkValue();
+            bool r2 = exp->e2->checkValue();
+            if (r1 || r2)
+                return setError();
+        }
+
+        TOK altop;
+        switch (exp->op)
+        {
+            // Refer rel_integral[] table
+            case TOKunord:  altop = TOKerror;       break;
+            case TOKlg:     altop = TOKnotequal;    break;
+            case TOKleg:    altop = TOKerror;       break;
+            case TOKule:    altop = TOKle;          break;
+            case TOKul:     altop = TOKlt;          break;
+            case TOKuge:    altop = TOKge;          break;
+            case TOKug:     altop = TOKgt;          break;
+            case TOKue:     altop = TOKequal;       break;
+            default:        altop = TOKreserved;    break;
+        }
+        if (altop == TOKerror &&
+            (t1->ty == Tarray || t1->ty == Tsarray ||
+             t2->ty == Tarray || t2->ty == Tsarray))
+        {
+            exp->error("'%s' is not defined for array comparisons", Token::toChars(exp->op));
+            return setError();
+        }
+        if (altop != TOKreserved)
+        {
+            if (!t1->isfloating())
+            {
+                if (altop == TOKerror)
+                {
+                    const char *s = exp->op == TOKunord ? "false" : "true";
+                    exp->error("floating point operator '%s' always returns %s for non-floating comparisons",
+                        Token::toChars(exp->op), s);
+                }
+                else
+                {
+                    exp->error("use '%s' for non-floating comparisons rather than floating point operator '%s'",
+                        Token::toChars(altop), Token::toChars(exp->op));
+                }
+            }
+            else
+            {
+                exp->error("use std.math.isNaN to deal with NaN operands rather than floating point operator '%s'",
+                    Token::toChars(exp->op));
+            }
+            result = new ErrorExp();
+            return;
+        }
+
+        //printf("CmpExp: %s, type = %s\n", e->toChars(), e->type->toChars());
+        result = exp;
+    }
+
+    void visit(EqualExp *exp)
+    {
+        //printf("EqualExp::semantic('%s')\n", toChars());
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        setNoderefOperands(exp);
+
+        if (Expression *e = binSemanticProp(exp, sc))
+        {
+            result = e;
+            return;
+        }
+        if (exp->e1->op == TOKtype || exp->e2->op == TOKtype)
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+
+        /* Before checking for operator overloading, check to see if we're
+         * comparing the addresses of two statics. If so, we can just see
+         * if they are the same symbol.
+         */
+        if (exp->e1->op == TOKaddress && exp->e2->op == TOKaddress)
+        {
+            AddrExp *ae1 = (AddrExp *)exp->e1;
+            AddrExp *ae2 = (AddrExp *)exp->e2;
+            if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar)
+            {
+                VarExp *ve1 = (VarExp *)ae1->e1;
+                VarExp *ve2 = (VarExp *)ae2->e1;
+
+                if (ve1->var == ve2->var)
+                {
+                    // They are the same, result is 'true' for ==, 'false' for !=
+                    result = new IntegerExp(exp->loc, (exp->op == TOKequal), Type::tbool);
+                    return;
+                }
+            }
+        }
+
+        if (Expression *e = exp->op_overload(sc))
+        {
+            result = e;
+            return;
+        }
+
+        if (Expression *e = typeCombine(exp, sc))
+        {
+            result = e;
+            return;
+        }
+
+        bool f1 = checkNonAssignmentArrayOp(exp->e1);
+        bool f2 = checkNonAssignmentArrayOp(exp->e2);
+        if (f1 || f2)
+            return setError();
+
+        exp->type = Type::tbool;
+
+        // Special handling for array comparisons
+        if (!arrayTypeCompatible(exp->loc, exp->e1->type, exp->e2->type))
+        {
+            if (exp->e1->type != exp->e2->type && exp->e1->type->isfloating() && exp->e2->type->isfloating())
+            {
+                // Cast both to complex
+                exp->e1 = exp->e1->castTo(sc, Type::tcomplex80);
+                exp->e2 = exp->e2->castTo(sc, Type::tcomplex80);
+            }
+        }
+        if (exp->e1->type->toBasetype()->ty == Taarray)
+            semanticTypeInfo(sc, exp->e1->type->toBasetype());
+
+        Type *t1 = exp->e1->type->toBasetype();
+        Type *t2 = exp->e2->type->toBasetype();
+
+        if (!Target::isVectorOpSupported(t1, exp->op, t2))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+
+        result = exp;
+    }
+
+    void visit(IdentityExp *exp)
+    {
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        setNoderefOperands(exp);
+
+        if (Expression *ex = binSemanticProp(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        if (Expression *ex = typeCombine(exp, sc))
+        {
+            result = ex;
+            return;
+        }
+
+        bool f1 = checkNonAssignmentArrayOp(exp->e1);
+        bool f2 = checkNonAssignmentArrayOp(exp->e2);
+        if (f1 || f2)
+            return setError();
+
+        exp->type = Type::tbool;
+
+        if (exp->e1->type != exp->e2->type && exp->e1->type->isfloating() && exp->e2->type->isfloating())
+        {
+            // Cast both to complex
+            exp->e1 = exp->e1->castTo(sc, Type::tcomplex80);
+            exp->e2 = exp->e2->castTo(sc, Type::tcomplex80);
+        }
+
+        Type *tb1 = exp->e1->type->toBasetype();
+        Type *tb2 = exp->e2->type->toBasetype();
+        if (!Target::isVectorOpSupported(tb1, exp->op, tb2))
+        {
+            result = exp->incompatibleTypes();
+            return;
+        }
+
+        result = exp;
+    }
+
+    void visit(CondExp *exp)
+    {
+#if LOGSEMANTIC
+        printf("CondExp::semantic('%s')\n", exp->toChars());
+#endif
+        if (exp->type)
+        {
+            result = exp;
+            return;
+        }
+
+        if (exp->econd->op == TOKdotid)
+            ((DotIdExp *)exp->econd)->noderef = true;
+
+        Expression *ec = semantic(exp->econd, sc);
+        ec = resolveProperties(sc, ec);
+        ec = ec->toBoolean(sc);
+
+        unsigned cs0 = sc->callSuper;
+        unsigned *fi0 = sc->saveFieldInit();
+        Expression *e1x = semantic(exp->e1, sc);
+        e1x = resolveProperties(sc, e1x);
+
+        unsigned cs1 = sc->callSuper;
+        unsigned *fi1 = sc->fieldinit;
+        sc->callSuper = cs0;
+        sc->fieldinit = fi0;
+        Expression *e2x = semantic(exp->e2, sc);
+        e2x = resolveProperties(sc, e2x);
+
+        sc->mergeCallSuper(exp->loc, cs1);
+        sc->mergeFieldInit(exp->loc, fi1);
+
+        if (ec->op == TOKerror)
+        {
+            result = ec;
+            return;
+        }
+        if (ec->type == Type::terror)
+            return setError();
+        exp->econd = ec;
+
+        if (e1x->op == TOKerror)
+        {
+            result = e1x;
+            return;
+        }
+        if (e1x->type == Type::terror)
+            return setError();
+        exp->e1 = e1x;
+
+        if (e2x->op == TOKerror)
+        {
+            result = e2x;
+            return;
+        }
+        if (e2x->type == Type::terror)
+            return setError();
+        exp->e2 = e2x;
+
+        bool f0 = checkNonAssignmentArrayOp(exp->econd);
+        bool f1 = checkNonAssignmentArrayOp(exp->e1);
+        bool f2 = checkNonAssignmentArrayOp(exp->e2);
+        if (f0 || f1 || f2)
+            return setError();
+
+        Type *t1 = exp->e1->type;
+        Type *t2 = exp->e2->type;
+        // If either operand is void the result is void, we have to cast both
+        // the expression to void so that we explicitly discard the expression
+        // value if any (bugzilla 16598)
+        if (t1->ty == Tvoid || t2->ty == Tvoid)
+        {
+            exp->type = Type::tvoid;
+            exp->e1 = exp->e1->castTo(sc, exp->type);
+            exp->e2 = exp->e2->castTo(sc, exp->type);
+        }
+        else if (t1 == t2)
+            exp->type = t1;
+        else
+        {
+            if (Expression *ex = typeCombine(exp, sc))
+            {
+                result = ex;
+                return;
+            }
+            switch (exp->e1->type->toBasetype()->ty)
+            {
+                case Tcomplex32:
+                case Tcomplex64:
+                case Tcomplex80:
+                    exp->e2 = exp->e2->castTo(sc, exp->e1->type);
+                    break;
+            }
+            switch (exp->e2->type->toBasetype()->ty)
+            {
+                case Tcomplex32:
+                case Tcomplex64:
+                case Tcomplex80:
+                    exp->e1 = exp->e1->castTo(sc, exp->e2->type);
+                    break;
+            }
+            if (exp->type->toBasetype()->ty == Tarray)
+            {
+                exp->e1 = exp->e1->castTo(sc, exp->type);
+                exp->e2 = exp->e2->castTo(sc, exp->type);
+            }
+        }
+        exp->type = exp->type->merge2();
+#if 0
+        printf("res: %s\n", exp->type->toChars());
+        printf("e1 : %s\n", exp->e1->type->toChars());
+        printf("e2 : %s\n", exp->e2->type->toChars());
+#endif
+
+        /* Bugzilla 14696: If either e1 or e2 contain temporaries which need dtor,
+         * make them conditional.
+         * Rewrite:
+         *      cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
+         * to:
+         *      (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
+         * and replace edtors of __tmp1 and __tmp2 with:
+         *      __tmp1->edtor --> __cond && __tmp1.dtor()
+         *      __tmp2->edtor --> __cond || __tmp2.dtor()
+         */
+        exp->hookDtors(sc);
+
+        result = exp;
+    }
+
+    void visit(FileInitExp *e)
+    {
+        //printf("FileInitExp::semantic()\n");
+        e->type = Type::tstring;
+        result = e;
+    }
+
+    void visit(LineInitExp *e)
+    {
+        e->type = Type::tint32;
+        result = e;
+    }
+
+    void visit(ModuleInitExp *e)
+    {
+        //printf("ModuleInitExp::semantic()\n");
+        e->type = Type::tstring;
+        result = e;
+    }
+
+    void visit(FuncInitExp *e)
+    {
+        //printf("FuncInitExp::semantic()\n");
+        e->type = Type::tstring;
+        if (sc->func)
+        {
+            result = e->resolveLoc(Loc(), sc);
+            return;
+        }
+        result = e;
+    }
+
+    void visit(PrettyFuncInitExp *e)
+    {
+        //printf("PrettyFuncInitExp::semantic()\n");
+        e->type = Type::tstring;
+        if (sc->func)
+        {
+            result = e->resolveLoc(Loc(), sc);
+            return;
+        }
+        result = e;
+    }
+};
+
+/**********************************
+ * Try to run semantic routines.
+ * If they fail, return NULL.
+ */
+Expression *trySemantic(Expression *exp, Scope* sc)
+{
+    //printf("+trySemantic(%s)\n", toChars());
+    unsigned errors = global.startGagging();
+    Expression *e = semantic(exp, sc);
+    if (global.endGagging(errors))
+    {
+        e = NULL;
+    }
+    //printf("-trySemantic(%s)\n", toChars());
+    return e;
+}
+
+/**************************
+ * Helper function for easy error propagation.
+ * If error occurs, returns ErrorExp. Otherwise returns NULL.
+ */
+Expression *unaSemantic(UnaExp *e, Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("UnaExp::semantic('%s')\n", e->toChars());
+#endif
+    Expression *e1x = semantic(e->e1, sc);
+    if (e1x->op == TOKerror)
+        return e1x;
+    e->e1 = e1x;
+    return NULL;
+}
+
+/**************************
+ * Helper function for easy error propagation.
+ * If error occurs, returns ErrorExp. Otherwise returns NULL.
+ */
+Expression *binSemantic(BinExp *e, Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("BinExp::semantic('%s')\n", e->toChars());
+#endif
+    Expression *e1x = semantic(e->e1, sc);
+    Expression *e2x = semantic(e->e2, sc);
+
+    // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+    if (e1x->op == TOKtype)
+        e1x = resolveAliasThis(sc, e1x);
+    if (e2x->op == TOKtype)
+        e2x = resolveAliasThis(sc, e2x);
+
+    if (e1x->op == TOKerror)
+        return e1x;
+    if (e2x->op == TOKerror)
+        return e2x;
+    e->e1 = e1x;
+    e->e2 = e2x;
+    return NULL;
+}
+
+Expression *binSemanticProp(BinExp *e, Scope *sc)
+{
+    if (Expression *ex = binSemantic(e, sc))
+        return ex;
+    Expression *e1x = resolveProperties(sc, e->e1);
+    Expression *e2x = resolveProperties(sc, e->e2);
+    if (e1x->op == TOKerror)
+        return e1x;
+    if (e2x->op == TOKerror)
+        return e2x;
+    e->e1 = e1x;
+    e->e2 = e2x;
+    return NULL;
+}
+
+// entrypoint for semantic ExpressionSemanticVisitor
+Expression *semantic(Expression *e, Scope *sc)
+{
+    ExpressionSemanticVisitor v = ExpressionSemanticVisitor(sc);
+    e->accept(&v);
+    return v.result;
+}
+
+Expression *semanticX(DotIdExp *exp, Scope *sc)
+{
+    //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
+    if (Expression *ex = unaSemantic(exp, sc))
+        return ex;
+
+    if (exp->ident == Id::_mangleof)
+    {
+        // symbol.mangleof
+        Dsymbol *ds;
+        switch (exp->e1->op)
+        {
+            case TOKscope:
+                ds = ((ScopeExp *)exp->e1)->sds;
+                goto L1;
+            case TOKvar:
+                ds = ((VarExp *)exp->e1)->var;
+                goto L1;
+            case TOKdotvar:
+                ds = ((DotVarExp *)exp->e1)->var;
+                goto L1;
+            case TOKoverloadset:
+                ds = ((OverExp *)exp->e1)->vars;
+                goto L1;
+            case TOKtemplate:
+                {
+                    TemplateExp *te = (TemplateExp *)exp->e1;
+                    ds = te->fd ? (Dsymbol *)te->fd : te->td;
+                }
+            L1:
+                {
+                    assert(ds);
+                    if (FuncDeclaration *f = ds->isFuncDeclaration())
+                    {
+                        if (f->checkForwardRef(exp->loc))
+                            return new ErrorExp();
+                    }
+                    OutBuffer buf;
+                    mangleToBuffer(ds, &buf);
+                    const char *s = buf.extractString();
+                    Expression *e = new StringExp(exp->loc, (void*)s, strlen(s));
+                    e = semantic(e, sc);
+                    return e;
+                }
+            default:
+                break;
+        }
+    }
+
+    if (exp->e1->op == TOKvar && exp->e1->type->toBasetype()->ty == Tsarray && exp->ident == Id::length)
+    {
+        // bypass checkPurity
+        return exp->e1->type->dotExp(sc, exp->e1, exp->ident, exp->noderef ? 2 : 0);
+    }
+
+    if (exp->e1->op == TOKdot)
+    {
+    }
+    else
+    {
+        exp->e1 = resolvePropertiesX(sc, exp->e1);
+    }
+    if (exp->e1->op == TOKtuple && exp->ident == Id::offsetof)
+    {
+        /* 'distribute' the .offsetof to each of the tuple elements.
+        */
+        TupleExp *te = (TupleExp *)exp->e1;
+        Expressions *exps = new Expressions();
+        exps->setDim(te->exps->dim);
+        for (size_t i = 0; i < exps->dim; i++)
+        {
+            Expression *e = (*te->exps)[i];
+            e = semantic(e, sc);
+            e = new DotIdExp(e->loc, e, Id::offsetof);
+            (*exps)[i] = e;
+        }
+        // Don't evaluate te->e0 in runtime
+        Expression *e = new TupleExp(exp->loc, NULL, exps);
+        e = semantic(e, sc);
+        return e;
+    }
+    if (exp->e1->op == TOKtuple && exp->ident == Id::length)
+    {
+        TupleExp *te = (TupleExp *)exp->e1;
+        // Don't evaluate te->e0 in runtime
+        Expression *e = new IntegerExp(exp->loc, te->exps->dim, Type::tsize_t);
+        return e;
+    }
+
+    // Bugzilla 14416: Template has no built-in properties except for 'stringof'.
+    if ((exp->e1->op == TOKdottd || exp->e1->op == TOKtemplate) && exp->ident != Id::stringof)
+    {
+        exp->error("template %s does not have property '%s'", exp->e1->toChars(), exp->ident->toChars());
+        return new ErrorExp();
+    }
+
+    if (!exp->e1->type)
+    {
+        exp->error("expression %s does not have property '%s'", exp->e1->toChars(), exp->ident->toChars());
+        return new ErrorExp();
+    }
+
+    return exp;
+}
+
+// Resolve e1.ident without seeing UFCS.
+// If flag == 1, stop "not a property" error and return NULL.
+Expression *semanticY(DotIdExp *exp, Scope *sc, int flag)
+{
+    //printf("DotIdExp::semanticY(this = %p, '%s')\n", this, toChars());
+
+    //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
+
+    /* Special case: rewrite this.id and super.id
+     * to be classtype.id and baseclasstype.id
+     * if we have no this pointer.
+     */
+    if ((exp->e1->op == TOKthis || exp->e1->op == TOKsuper) && !hasThis(sc))
+    {
+        if (AggregateDeclaration *ad = sc->getStructClassScope())
+        {
+            if (exp->e1->op == TOKthis)
+            {
+                exp->e1 = new TypeExp(exp->e1->loc, ad->type);
+            }
+            else
+            {
+                ClassDeclaration *cd = ad->isClassDeclaration();
+                if (cd && cd->baseClass)
+                    exp->e1 = new TypeExp(exp->e1->loc, cd->baseClass->type);
+            }
+        }
+    }
+
+    Expression *e = semanticX(exp, sc);
+    if (e != exp)
+        return e;
+
+    Expression *eleft;
+    Expression *eright;
+    if (exp->e1->op == TOKdot)
+    {
+        DotExp *de = (DotExp *)exp->e1;
+        eleft = de->e1;
+        eright = de->e2;
+    }
+    else
+    {
+        eleft = NULL;
+        eright = exp->e1;
+    }
+
+    Type *t1b = exp->e1->type->toBasetype();
+
+    if (eright->op == TOKscope)        // also used for template alias's
+    {
+        ScopeExp *ie = (ScopeExp *)eright;
+        int flags = SearchLocalsOnly;
+
+        /* Disable access to another module's private imports.
+         * The check for 'is sds our current module' is because
+         * the current module should have access to its own imports.
+         */
+        if (ie->sds->isModule() && ie->sds != sc->_module)
+            flags |= IgnorePrivateImports;
+        if (sc->flags & SCOPEignoresymbolvisibility)
+            flags |= IgnoreSymbolVisibility;
+        Dsymbol *s = ie->sds->search(exp->loc, exp->ident, flags);
+        /* Check for visibility before resolving aliases because public
+         * aliases to private symbols are public.
+         */
+        if (s && !(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc->_module, s))
+        {
+            if (s->isDeclaration())
+                ::error(exp->loc, "%s is not visible from module %s", s->toPrettyChars(), sc->_module->toChars());
+            else
+                ::deprecation(exp->loc, "%s is not visible from module %s", s->toPrettyChars(), sc->_module->toChars());
+            // s = NULL
+        }
+        if (s)
+        {
+            if (Package *p = s->isPackage())
+                checkAccess(exp->loc, sc, p);
+
+            // if 's' is a tuple variable, the tuple is returned.
+            s = s->toAlias();
+
+            exp->checkDeprecated(sc, s);
+
+            EnumMember *em = s->isEnumMember();
+            if (em)
+            {
+                return em->getVarExp(exp->loc, sc);
+            }
+
+            VarDeclaration *v = s->isVarDeclaration();
+            if (v)
+            {
+                //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars());
+                if (!v->type ||
+                    !v->type->deco && v->inuse)
+                {
+                    if (v->inuse)
+                        exp->error("circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+                    else
+                        exp->error("forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+                    return new ErrorExp();
+                }
+                if (v->type->ty == Terror)
+                    return new ErrorExp();
+
+                if ((v->storage_class & STCmanifest) && v->_init && !exp->wantsym)
+                {
+                    /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
+                     * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
+                     * be reverted. `wantsym` is the hack to work around the problem.
+                     */
+                    if (v->inuse)
+                    {
+                        ::error(exp->loc, "circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+                        return new ErrorExp();
+                    }
+                    e = v->expandInitializer(exp->loc);
+                    v->inuse++;
+                    e = semantic(e, sc);
+                    v->inuse--;
+                    return e;
+                }
+
+                if (v->needThis())
+                {
+                    if (!eleft)
+                        eleft = new ThisExp(exp->loc);
+                    e = new DotVarExp(exp->loc, eleft, v);
+                    e = semantic(e, sc);
+                }
+                else
+                {
+                    e = new VarExp(exp->loc, v);
+                    if (eleft)
+                    {   e = new CommaExp(exp->loc, eleft, e);
+                        e->type = v->type;
+                    }
+                }
+                e = e->deref();
+                return semantic(e, sc);
+            }
+
+            FuncDeclaration *f = s->isFuncDeclaration();
+            if (f)
+            {
+                //printf("it's a function\n");
+                if (!f->functionSemantic())
+                    return new ErrorExp();
+                if (f->needThis())
+                {
+                    if (!eleft)
+                        eleft = new ThisExp(exp->loc);
+                    e = new DotVarExp(exp->loc, eleft, f, true);
+                    e = semantic(e, sc);
+                }
+                else
+                {
+                    e = new VarExp(exp->loc, f, true);
+                    if (eleft)
+                    {   e = new CommaExp(exp->loc, eleft, e);
+                        e->type = f->type;
+                    }
+                }
+                return e;
+            }
+            if (OverDeclaration *od = s->isOverDeclaration())
+            {
+                e = new VarExp(exp->loc, od, true);
+                if (eleft)
+                {
+                    e = new CommaExp(exp->loc, eleft, e);
+                    e->type = Type::tvoid;  // ambiguous type?
+                }
+                return e;
+            }
+            OverloadSet *o = s->isOverloadSet();
+            if (o)
+            {   //printf("'%s' is an overload set\n", o->toChars());
+                return new OverExp(exp->loc, o);
+            }
+
+            Type *t = s->getType();
+            if (t)
+            {
+                return new TypeExp(exp->loc, t);
+            }
+
+            TupleDeclaration *tup = s->isTupleDeclaration();
+            if (tup)
+            {
+                if (eleft)
+                {
+                    e = new DotVarExp(exp->loc, eleft, tup);
+                    e = semantic(e, sc);
+                    return e;
+                }
+                e = new TupleExp(exp->loc, tup);
+                e = semantic(e, sc);
+                return e;
+            }
+
+            ScopeDsymbol *sds = s->isScopeDsymbol();
+            if (sds)
+            {
+                //printf("it's a ScopeDsymbol %s\n", exp->ident->toChars());
+                e = new ScopeExp(exp->loc, sds);
+                e = semantic(e, sc);
+                if (eleft)
+                    e = new DotExp(exp->loc, eleft, e);
+                return e;
+            }
+
+            Import *imp = s->isImport();
+            if (imp)
+            {
+                ie = new ScopeExp(exp->loc, imp->pkg);
+                return semantic(ie, sc);
+            }
+
+            // BUG: handle other cases like in IdentifierExp::semantic()
+#ifdef DEBUG
+            printf("s = '%s', kind = '%s'\n", s->toChars(), s->kind());
+#endif
+            assert(0);
+        }
+        else if (exp->ident == Id::stringof)
+        {
+            const char *p = ie->toChars();
+            e = new StringExp(exp->loc, (char*)p, strlen(p));
+            e = semantic(e, sc);
+            return e;
+        }
+        if (ie->sds->isPackage() ||
+            ie->sds->isImport() ||
+            ie->sds->isModule())
+        {
+            flag = 0;
+        }
+        if (flag)
+            return NULL;
+        s = ie->sds->search_correct(exp->ident);
+        if (s)
+            exp->error("undefined identifier '%s' in %s '%s', did you mean %s '%s'?",
+                       exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars(), s->kind(), s->toChars());
+        else
+            exp->error("undefined identifier '%s' in %s '%s'",
+                       exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars());
+        return new ErrorExp();
+    }
+    else if (t1b->ty == Tpointer && exp->e1->type->ty != Tenum &&
+             exp->ident != Id::_init && exp->ident != Id::__sizeof &&
+             exp->ident != Id::__xalignof && exp->ident != Id::offsetof &&
+             exp->ident != Id::_mangleof && exp->ident != Id::stringof)
+    {
+        Type *t1bn = t1b->nextOf();
+        if (flag)
+        {
+            AggregateDeclaration *ad = isAggregate(t1bn);
+            if (ad && !ad->members)   // Bugzilla 11312
+                return NULL;
+        }
+
+        /* Rewrite:
+         *   p.ident
+         * as:
+         *   (*p).ident
+         */
+        if (flag && t1bn->ty == Tvoid)
+            return NULL;
+        e = new PtrExp(exp->loc, exp->e1);
+        e = semantic(e, sc);
+        return e->type->dotExp(sc, e, exp->ident, flag | (exp->noderef ? 2 : 0));
+    }
+    else
+    {
+        if (exp->e1->op == TOKtype || exp->e1->op == TOKtemplate)
+            flag = 0;
+        e = exp->e1->type->dotExp(sc, exp->e1, exp->ident, flag | (exp->noderef ? 2 : 0));
+        if (!flag || e)
+            e = semantic(e, sc);
+        return e;
+    }
+}
+
+// Resolve e1.ident!tiargs without seeing UFCS.
+// If flag == 1, stop "not a property" error and return NULL.
+Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag)
+{
+#if LOGSEMANTIC
+    printf("DotTemplateInstanceExpY::semantic('%s')\n", exp->toChars());
+#endif
+
+    DotIdExp *die = new DotIdExp(exp->loc, exp->e1, exp->ti->name);
+
+    Expression *e = semanticX(die, sc);
+    if (e == die)
+    {
+        exp->e1 = die->e1;   // take back
+
+        Type *t1b = exp->e1->type->toBasetype();
+        if (t1b->ty == Tarray || t1b->ty == Tsarray || t1b->ty == Taarray ||
+            t1b->ty == Tnull  || (t1b->isTypeBasic() && t1b->ty != Tvoid))
+        {
+            /* No built-in type has templatized properties, so do shortcut.
+             * It is necessary in: 1024.max!"a < b"
+             */
+            if (flag)
+                return NULL;
+        }
+        e = semanticY(die, sc, flag);
+        if (flag && e && isDotOpDispatch(e))
+        {
+            /* opDispatch!tiargs would be a function template that needs IFTI,
+             * so it's not a template
+             */
+            e = NULL;   /* fall down to UFCS */
+        }
+        if (flag && !e)
+            return NULL;
+    }
+    assert(e);
+
+L1:
+    if (e->op == TOKerror)
+        return e;
+    if (e->op == TOKdotvar)
+    {
+        DotVarExp *dve = (DotVarExp *)e;
+        if (FuncDeclaration *fd = dve->var->isFuncDeclaration())
+        {
+            TemplateDeclaration *td = fd->findTemplateDeclRoot();
+            if (td)
+            {
+                e = new DotTemplateExp(dve->loc, dve->e1, td);
+                e = semantic(e, sc);
+            }
+        }
+        else if (OverDeclaration *od = dve->var->isOverDeclaration())
+        {
+            exp->e1 = dve->e1;   // pull semantic() result
+            if (!exp->findTempDecl(sc))
+                goto Lerr;
+            if (exp->ti->needsTypeInference(sc))
+                return exp;
+            exp->ti->semantic(sc);
+            if (!exp->ti->inst || exp->ti->errors)    // if template failed to expand
+                return new ErrorExp();
+            Dsymbol *s = exp->ti->toAlias();
+            Declaration *v = s->isDeclaration();
+            if (v)
+            {
+                if (v->type && !v->type->deco)
+                    v->type = v->type->semantic(v->loc, sc);
+                e = new DotVarExp(exp->loc, exp->e1, v);
+                e = semantic(e, sc);
+                return e;
+            }
+            e = new ScopeExp(exp->loc, exp->ti);
+            e = new DotExp(exp->loc, exp->e1, e);
+            e = semantic(e, sc);
+            return e;
+        }
+    }
+    else if (e->op == TOKvar)
+    {
+        VarExp *ve = (VarExp *)e;
+        if (FuncDeclaration *fd = ve->var->isFuncDeclaration())
+        {
+            TemplateDeclaration *td = fd->findTemplateDeclRoot();
+            if (td)
+            {
+                e = new ScopeExp(ve->loc, td);
+                e = semantic(e, sc);
+            }
+        }
+        else if (OverDeclaration *od = ve->var->isOverDeclaration())
+        {
+            exp->ti->tempdecl = od;
+            e = new ScopeExp(exp->loc, exp->ti);
+            e = semantic(e, sc);
+            return e;
+        }
+    }
+    if (e->op == TOKdottd)
+    {
+        DotTemplateExp *dte = (DotTemplateExp *)e;
+        exp->e1 = dte->e1;   // pull semantic() result
+
+        exp->ti->tempdecl = dte->td;
+        if (!exp->ti->semanticTiargs(sc))
+            return new ErrorExp();
+        if (exp->ti->needsTypeInference(sc))
+            return exp;
+        exp->ti->semantic(sc);
+        if (!exp->ti->inst || exp->ti->errors)    // if template failed to expand
+            return new ErrorExp();
+        Dsymbol *s = exp->ti->toAlias();
+        Declaration *v = s->isDeclaration();
+        if (v && (v->isFuncDeclaration() || v->isVarDeclaration()))
+        {
+            e = new DotVarExp(exp->loc, exp->e1, v);
+            e = semantic(e, sc);
+            return e;
+        }
+        if (exp->e1->op == TOKtype)
+        {
+            e = resolve(exp->loc, sc, s, false);
+            return e;
+        }
+        e = new ScopeExp(exp->loc, exp->ti);
+        e = new DotExp(exp->loc, exp->e1, e);
+        e = semantic(e, sc);
+        return e;
+    }
+    else if (e->op == TOKscope)
+    {
+        ScopeExp *se = (ScopeExp *)e;
+        TemplateDeclaration *td = se->sds->isTemplateDeclaration();
+        if (!td)
+        {
+            exp->error("%s is not a template", e->toChars());
+            return new ErrorExp();
+        }
+        exp->ti->tempdecl = td;
+        e = new ScopeExp(exp->loc, exp->ti);
+        e = semantic(e, sc);
+        return e;
+    }
+    else if (e->op == TOKdot)
+    {
+        DotExp *de = (DotExp *)e;
+        exp->e1 = de->e1;    // pull semantic() result
+
+        if (de->e2->op == TOKoverloadset)
+        {
+            if (!exp->findTempDecl(sc) ||
+                !exp->ti->semanticTiargs(sc))
+            {
+                return new ErrorExp();
+            }
+            if (exp->ti->needsTypeInference(sc))
+                return exp;
+            exp->ti->semantic(sc);
+            if (!exp->ti->inst || exp->ti->errors)    // if template failed to expand
+                return new ErrorExp();
+            Dsymbol *s = exp->ti->toAlias();
+            Declaration *v = s->isDeclaration();
+            if (v)
+            {
+                if (v->type && !v->type->deco)
+                    v->type = v->type->semantic(v->loc, sc);
+                e = new DotVarExp(exp->loc, exp->e1, v);
+                e = semantic(e, sc);
+                return e;
+            }
+            e = new ScopeExp(exp->loc, exp->ti);
+            e = new DotExp(exp->loc, exp->e1, e);
+            e = semantic(e, sc);
+            return e;
+        }
+
+        if (de->e2->op == TOKscope)
+        {
+            // This should *really* be moved to ScopeExp::semantic()
+            ScopeExp *se = (ScopeExp *)de->e2;
+            de->e2 = resolve(exp->loc, sc, se->sds, false);
+        }
+
+        if (de->e2->op == TOKtemplate)
+        {
+            TemplateExp *te = (TemplateExp *) de->e2;
+            e = new DotTemplateExp(exp->loc,de->e1,te->td);
+        }
+        else
+            goto Lerr;
+
+        e = semantic(e, sc);
+        if (e == de)
+            goto Lerr;
+        goto L1;
+    }
+    else if (e->op == TOKoverloadset)
+    {
+        OverExp *oe = (OverExp *)e;
+        exp->ti->tempdecl = oe->vars;
+        e = new ScopeExp(exp->loc, exp->ti);
+        e = semantic(e, sc);
+        return e;
+    }
+Lerr:
+    e->error("%s isn't a template", e->toChars());
+    return new ErrorExp();
+}
diff --git a/gcc/d/dfrontend/file.c b/gcc/d/dfrontend/file.c
new file mode 100644
index 00000000000..98afcf697a2
--- /dev/null
+++ b/gcc/d/dfrontend/file.c
@@ -0,0 +1,266 @@
+
+/* Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/file.c
+ */
+
+#include "file.h"
+
+#if defined (__sun)
+#include <alloca.h>
+#endif
+
+#if _MSC_VER ||__MINGW32__
+#include <malloc.h>
+#include <string>
+#endif
+
+#if _WIN32
+#include <windows.h>
+#include <direct.h>
+#include <errno.h>
+#endif
+
+#if POSIX
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <utime.h>
+#endif
+
+#include "filename.h"
+#include "array.h"
+#include "rmem.h"
+
+/****************************** File ********************************/
+
+File::File(const FileName *n)
+{
+    ref = 0;
+    buffer = NULL;
+    len = 0;
+    name = (FileName *)n;
+}
+
+File *File::create(const char *n)
+{
+    return new File(n);
+}
+
+File::File(const char *n)
+{
+    ref = 0;
+    buffer = NULL;
+    len = 0;
+    name = new FileName(n);
+}
+
+File::~File()
+{
+    if (buffer)
+    {
+        if (ref == 0)
+            mem.xfree(buffer);
+#if _WIN32
+        if (ref == 2)
+            UnmapViewOfFile(buffer);
+#endif
+    }
+}
+
+/*************************************
+ */
+
+bool File::read()
+{
+    if (len)
+        return false;               // already read the file
+#if POSIX
+    size_t size;
+    struct stat buf;
+    ssize_t numread;
+
+    const char *name = this->name->toChars();
+    //printf("File::read('%s')\n",name);
+    int fd = open(name, O_RDONLY);
+    if (fd == -1)
+    {
+        //printf("\topen error, errno = %d\n",errno);
+        goto err1;
+    }
+
+    if (!ref)
+        ::free(buffer);
+    ref = 0;       // we own the buffer now
+
+    //printf("\tfile opened\n");
+    if (fstat(fd, &buf))
+    {
+        printf("\tfstat error, errno = %d\n",errno);
+        goto err2;
+    }
+    size = (size_t)buf.st_size;
+    buffer = (unsigned char *) ::malloc(size + 2);
+    if (!buffer)
+    {
+        printf("\tmalloc error, errno = %d\n",errno);
+        goto err2;
+    }
+
+    numread = ::read(fd, buffer, size);
+    if (numread != size)
+    {
+        printf("\tread error, errno = %d\n",errno);
+        goto err2;
+    }
+
+    if (close(fd) == -1)
+    {
+        printf("\tclose error, errno = %d\n",errno);
+        goto err;
+    }
+
+    len = size;
+
+    // Always store a wchar ^Z past end of buffer so scanner has a sentinel
+    buffer[size] = 0;           // ^Z is obsolete, use 0
+    buffer[size + 1] = 0;
+    return false;
+
+err2:
+    close(fd);
+err:
+    ::free(buffer);
+    buffer = NULL;
+    len = 0;
+
+err1:
+    return true;
+#elif _WIN32
+    DWORD size;
+    DWORD numread;
+
+    const char *name = this->name->toChars();
+    HANDLE h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
+        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
+    if (h == INVALID_HANDLE_VALUE)
+        goto err1;
+
+    if (!ref)
+        ::free(buffer);
+    ref = 0;
+
+    size = GetFileSize(h,NULL);
+    buffer = (unsigned char *) ::malloc(size + 2);
+    if (!buffer)
+        goto err2;
+
+    if (ReadFile(h,buffer,size,&numread,NULL) != TRUE)
+        goto err2;
+
+    if (numread != size)
+        goto err2;
+
+    if (!CloseHandle(h))
+        goto err;
+
+    len = size;
+
+    // Always store a wchar ^Z past end of buffer so scanner has a sentinel
+    buffer[size] = 0;           // ^Z is obsolete, use 0
+    buffer[size + 1] = 0;
+    return 0;
+
+err2:
+    CloseHandle(h);
+err:
+    ::free(buffer);
+    buffer = NULL;
+    len = 0;
+
+err1:
+    return true;
+#else
+    assert(0);
+#endif
+}
+
+/*********************************************
+ * Write a file.
+ * Returns:
+ *      false       success
+ */
+
+bool File::write()
+{
+#if POSIX
+    ssize_t numwritten;
+
+    const char *name = this->name->toChars();
+    int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4);
+    if (fd == -1)
+        goto err;
+
+    numwritten = ::write(fd, buffer, len);
+    if (len != numwritten)
+        goto err2;
+
+    if (close(fd) == -1)
+        goto err;
+
+    return false;
+
+err2:
+    close(fd);
+    ::remove(name);
+err:
+    return true;
+#elif _WIN32
+    DWORD numwritten;
+
+    const char *name = this->name->toChars();
+    HANDLE h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
+        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
+    if (h == INVALID_HANDLE_VALUE)
+        goto err;
+
+    if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
+        goto err2;
+
+    if (len != numwritten)
+        goto err2;
+
+    if (!CloseHandle(h))
+        goto err;
+    return false;
+
+err2:
+    CloseHandle(h);
+    DeleteFileA(name);
+err:
+    return true;
+#else
+    assert(0);
+#endif
+}
+
+void File::remove()
+{
+#if POSIX
+    int dummy = ::remove(this->name->toChars());
+#elif _WIN32
+    DeleteFileA(this->name->toChars());
+#else
+    assert(0);
+#endif
+}
+
+const char *File::toChars()
+{
+    return name->toChars();
+}
diff --git a/gcc/d/dfrontend/file.h b/gcc/d/dfrontend/file.h
new file mode 100644
index 00000000000..f73ec550c66
--- /dev/null
+++ b/gcc/d/dfrontend/file.h
@@ -0,0 +1,62 @@
+
+/* Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/dlang/dmd/blob/master/src/root/file.h
+ */
+
+#ifndef FILE_H
+#define FILE_H
+
+#if __DMC__
+#pragma once
+#endif
+
+#include <stddef.h>
+
+#include "array.h"
+
+typedef Array<struct File *> Files;
+
+struct FileName;
+
+struct File
+{
+    int ref;                    // != 0 if this is a reference to someone else's buffer
+    unsigned char *buffer;      // data for our file
+    size_t len;                 // amount of data in buffer[]
+
+    FileName *name;             // name of our file
+
+    File(const char *);
+    static File *create(const char *);
+    File(const FileName *);
+    ~File();
+
+    const char *toChars();
+
+    /* Read file, return true if error
+     */
+
+    bool read();
+
+    /* Write file, return true if error
+     */
+
+    bool write();
+
+    /* Set buffer
+     */
+
+    void setbuffer(void *buffer, size_t len)
+    {
+        this->buffer = (unsigned char *)buffer;
+        this->len = len;
+    }
+
+    void remove();              // delete file
+};
+
+#endif
diff --git a/gcc/d/dfrontend/filename.c b/gcc/d/dfrontend/filename.c
new file mode 100644
index 00000000000..42f8f5df41b
--- /dev/null
+++ b/gcc/d/dfrontend/filename.c
@@ -0,0 +1,672 @@
+
+/* Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/filename.c
+ */
+
+#include "filename.h"
+
+#include <stdint.h>
+#include <ctype.h>
+
+#include "outbuffer.h"
+#include "array.h"
+#include "file.h"
+#include "rmem.h"
+
+#if defined (__sun)
+#include <alloca.h>
+#endif
+
+#if _MSC_VER ||__MINGW32__
+#include <malloc.h>
+#include <string>
+#endif
+
+#if _WIN32
+#include <windows.h>
+#include <direct.h>
+#include <errno.h>
+#endif
+
+#if POSIX
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <utime.h>
+#endif
+
+/****************************** FileName ********************************/
+
+FileName::FileName(const char *str)
+    : str(mem.xstrdup(str))
+{
+}
+
+const char *FileName::combine(const char *path, const char *name)
+{   char *f;
+    size_t pathlen;
+    size_t namelen;
+
+    if (!path || !*path)
+        return (char *)name;
+    pathlen = strlen(path);
+    namelen = strlen(name);
+    f = (char *)mem.xmalloc(pathlen + 1 + namelen + 1);
+    memcpy(f, path, pathlen);
+#if POSIX
+    if (path[pathlen - 1] != '/')
+    {   f[pathlen] = '/';
+        pathlen++;
+    }
+#elif _WIN32
+    if (path[pathlen - 1] != '\\' &&
+        path[pathlen - 1] != '/'  &&
+        path[pathlen - 1] != ':')
+    {   f[pathlen] = '\\';
+        pathlen++;
+    }
+#else
+    assert(0);
+#endif
+    memcpy(f + pathlen, name, namelen + 1);
+    return f;
+}
+
+// Split a path into an Array of paths
+Strings *FileName::splitPath(const char *path)
+{
+    char c = 0;                         // unnecessary initializer is for VC /W4
+    const char *p;
+    OutBuffer buf;
+    Strings *array;
+
+    array = new Strings();
+    if (path)
+    {
+        p = path;
+        do
+        {   char instring = 0;
+
+            while (isspace((utf8_t)*p))         // skip leading whitespace
+                p++;
+            buf.reserve(strlen(p) + 1); // guess size of path
+            for (; ; p++)
+            {
+                c = *p;
+                switch (c)
+                {
+                    case '"':
+                        instring ^= 1;  // toggle inside/outside of string
+                        continue;
+
+#if MACINTOSH
+                    case ',':
+#endif
+#if _WIN32
+                    case ';':
+#endif
+#if POSIX
+                    case ':':
+#endif
+                        p++;
+                        break;          // note that ; cannot appear as part
+                                        // of a path, quotes won't protect it
+
+                    case 0x1A:          // ^Z means end of file
+                    case 0:
+                        break;
+
+                    case '\r':
+                        continue;       // ignore carriage returns
+
+#if POSIX
+                    case '~':
+                    {
+                        char *home = getenv("HOME");
+                        if (home)
+                            buf.writestring(home);
+                        else
+                            buf.writestring("~");
+                        continue;
+                    }
+#endif
+
+#if 0
+                    case ' ':
+                    case '\t':          // tabs in filenames?
+                        if (!instring)  // if not in string
+                            break;      // treat as end of path
+#endif
+                    default:
+                        buf.writeByte(c);
+                        continue;
+                }
+                break;
+            }
+            if (buf.offset)             // if path is not empty
+            {
+                array->push(buf.extractString());
+            }
+        } while (c);
+    }
+    return array;
+}
+
+int FileName::compare(RootObject *obj)
+{
+    return compare(str, ((FileName *)obj)->str);
+}
+
+int FileName::compare(const char *name1, const char *name2)
+{
+#if _WIN32
+    return stricmp(name1, name2);
+#else
+    return strcmp(name1, name2);
+#endif
+}
+
+bool FileName::equals(RootObject *obj)
+{
+    return compare(obj) == 0;
+}
+
+bool FileName::equals(const char *name1, const char *name2)
+{
+    return compare(name1, name2) == 0;
+}
+
+/************************************
+ * Return !=0 if absolute path name.
+ */
+
+bool FileName::absolute(const char *name)
+{
+#if _WIN32
+    return (*name == '\\') ||
+           (*name == '/')  ||
+           (*name && name[1] == ':');
+#elif POSIX
+    return (*name == '/');
+#else
+    assert(0);
+#endif
+}
+
+/********************************
+ * Return filename extension (read-only).
+ * Points past '.' of extension.
+ * If there isn't one, return NULL.
+ */
+
+const char *FileName::ext(const char *str)
+{
+    size_t len = strlen(str);
+
+    const char *e = str + len;
+    for (;;)
+    {
+        switch (*e)
+        {   case '.':
+                return e + 1;
+#if POSIX
+            case '/':
+                break;
+#endif
+#if _WIN32
+            case '\\':
+            case ':':
+            case '/':
+                break;
+#endif
+            default:
+                if (e == str)
+                    break;
+                e--;
+                continue;
+        }
+        return NULL;
+    }
+}
+
+const char *FileName::ext()
+{
+    return ext(str);
+}
+
+/********************************
+ * Return mem.xmalloc'd filename with extension removed.
+ */
+
+const char *FileName::removeExt(const char *str)
+{
+    const char *e = ext(str);
+    if (e)
+    {   size_t len = (e - str) - 1;
+        char *n = (char *)mem.xmalloc(len + 1);
+        memcpy(n, str, len);
+        n[len] = 0;
+        return n;
+    }
+    return mem.xstrdup(str);
+}
+
+/********************************
+ * Return filename name excluding path (read-only).
+ */
+
+const char *FileName::name(const char *str)
+{
+    size_t len = strlen(str);
+
+    const char *e = str + len;
+    for (;;)
+    {
+        switch (*e)
+        {
+#if POSIX
+            case '/':
+               return e + 1;
+#endif
+#if _WIN32
+            case '/':
+            case '\\':
+                return e + 1;
+            case ':':
+                /* The ':' is a drive letter only if it is the second
+                 * character or the last character,
+                 * otherwise it is an ADS (Alternate Data Stream) separator.
+                 * Consider ADS separators as part of the file name.
+                 */
+                if (e == str + 1 || e == str + len - 1)
+                    return e + 1;
+#endif
+            default:
+                if (e == str)
+                    break;
+                e--;
+                continue;
+        }
+        return e;
+    }
+}
+
+const char *FileName::name()
+{
+    return name(str);
+}
+
+/**************************************
+ * Return path portion of str.
+ * Path will does not include trailing path separator.
+ */
+
+const char *FileName::path(const char *str)
+{
+    const char *n = name(str);
+    size_t pathlen;
+
+    if (n > str)
+    {
+#if POSIX
+        if (n[-1] == '/')
+            n--;
+#elif _WIN32
+        if (n[-1] == '\\' || n[-1] == '/')
+            n--;
+#else
+        assert(0);
+#endif
+    }
+    pathlen = n - str;
+    char *path = (char *)mem.xmalloc(pathlen + 1);
+    memcpy(path, str, pathlen);
+    path[pathlen] = 0;
+    return path;
+}
+
+/**************************************
+ * Replace filename portion of path.
+ */
+
+const char *FileName::replaceName(const char *path, const char *name)
+{
+    size_t pathlen;
+    size_t namelen;
+
+    if (absolute(name))
+        return name;
+
+    const char *n = FileName::name(path);
+    if (n == path)
+        return name;
+    pathlen = n - path;
+    namelen = strlen(name);
+    char *f = (char *)mem.xmalloc(pathlen + 1 + namelen + 1);
+    memcpy(f, path, pathlen);
+#if POSIX
+    if (path[pathlen - 1] != '/')
+    {   f[pathlen] = '/';
+        pathlen++;
+    }
+#elif _WIN32
+    if (path[pathlen - 1] != '\\' &&
+        path[pathlen - 1] != '/' &&
+        path[pathlen - 1] != ':')
+    {   f[pathlen] = '\\';
+        pathlen++;
+    }
+#else
+    assert(0);
+#endif
+    memcpy(f + pathlen, name, namelen + 1);
+    return f;
+}
+
+/***************************
+ * Free returned value with FileName::free()
+ */
+
+const char *FileName::defaultExt(const char *name, const char *ext)
+{
+    const char *e = FileName::ext(name);
+    if (e)                              // if already has an extension
+        return mem.xstrdup(name);
+
+    size_t len = strlen(name);
+    size_t extlen = strlen(ext);
+    char *s = (char *)mem.xmalloc(len + 1 + extlen + 1);
+    memcpy(s,name,len);
+    s[len] = '.';
+    memcpy(s + len + 1, ext, extlen + 1);
+    return s;
+}
+
+/***************************
+ * Free returned value with FileName::free()
+ */
+
+const char *FileName::forceExt(const char *name, const char *ext)
+{
+    const char *e = FileName::ext(name);
+    if (e)                              // if already has an extension
+    {
+        size_t len = e - name;
+        size_t extlen = strlen(ext);
+
+        char *s = (char *)mem.xmalloc(len + extlen + 1);
+        memcpy(s,name,len);
+        memcpy(s + len, ext, extlen + 1);
+        return s;
+    }
+    else
+        return defaultExt(name, ext);   // doesn't have one
+}
+
+/******************************
+ * Return !=0 if extensions match.
+ */
+
+bool FileName::equalsExt(const char *ext)
+{
+    return equalsExt(str, ext);
+}
+
+bool FileName::equalsExt(const char *name, const char *ext)
+{
+    const char *e = FileName::ext(name);
+    if (!e && !ext)
+        return true;
+    if (!e || !ext)
+        return false;
+    return FileName::compare(e, ext) == 0;
+}
+
+/*************************************
+ * Search Path for file.
+ * Input:
+ *      cwd     if true, search current directory before searching path
+ */
+
+const char *FileName::searchPath(Strings *path, const char *name, bool cwd)
+{
+    if (absolute(name))
+    {
+        return exists(name) ? name : NULL;
+    }
+    if (cwd)
+    {
+        if (exists(name))
+            return name;
+    }
+    if (path)
+    {
+
+        for (size_t i = 0; i < path->dim; i++)
+        {
+            const char *p = (*path)[i];
+            const char *n = combine(p, name);
+
+            if (exists(n))
+                return n;
+        }
+    }
+    return NULL;
+}
+
+
+/*************************************
+ * Search Path for file in a safe manner.
+ *
+ * Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
+ * ('Path Traversal') attacks.
+ *      http://cwe.mitre.org/data/definitions/22.html
+ * More info:
+ *      https://www.securecoding.cert.org/confluence/display/seccode/FIO02-C.+Canonicalize+path+names+originating+from+untrusted+sources
+ * Returns:
+ *      NULL    file not found
+ *      !=NULL  mem.xmalloc'd file name
+ */
+
+const char *FileName::safeSearchPath(Strings *path, const char *name)
+{
+#if _WIN32
+    /* Disallow % / \ : and .. in name characters
+     */
+    for (const char *p = name; *p; p++)
+    {
+        char c = *p;
+        if (c == '\\' || c == '/' || c == ':' || c == '%' ||
+            (c == '.' && p[1] == '.'))
+        {
+            return NULL;
+        }
+    }
+
+    return FileName::searchPath(path, name, false);
+#elif POSIX
+    /* Even with realpath(), we must check for // and disallow it
+     */
+    for (const char *p = name; *p; p++)
+    {
+        char c = *p;
+        if (c == '/' && p[1] == '/')
+        {
+            return NULL;
+        }
+    }
+
+    if (path)
+    {
+        /* Each path is converted to a cannonical name and then a check is done to see
+         * that the searched name is really a child one of the the paths searched.
+         */
+        for (size_t i = 0; i < path->dim; i++)
+        {
+            const char *cname = NULL;
+            const char *cpath = canonicalName((*path)[i]);
+            //printf("FileName::safeSearchPath(): name=%s; path=%s; cpath=%s\n",
+            //      name, (char *)path->data[i], cpath);
+            if (cpath == NULL)
+                goto cont;
+            cname = canonicalName(combine(cpath, name));
+            //printf("FileName::safeSearchPath(): cname=%s\n", cname);
+            if (cname == NULL)
+                goto cont;
+            //printf("FileName::safeSearchPath(): exists=%i "
+            //      "strncmp(cpath, cname, %i)=%i\n", exists(cname),
+            //      strlen(cpath), strncmp(cpath, cname, strlen(cpath)));
+            // exists and name is *really* a "child" of path
+            if (exists(cname) && strncmp(cpath, cname, strlen(cpath)) == 0)
+            {
+                ::free((void *)cpath);
+                const char *p = mem.xstrdup(cname);
+                ::free((void *)cname);
+                return p;
+            }
+cont:
+            if (cpath)
+                ::free((void *)cpath);
+            if (cname)
+                ::free((void *)cname);
+        }
+    }
+    return NULL;
+#else
+    assert(0);
+#endif
+}
+
+
+int FileName::exists(const char *name)
+{
+#if POSIX
+    struct stat st;
+
+    if (stat(name, &st) < 0)
+        return 0;
+    if (S_ISDIR(st.st_mode))
+        return 2;
+    return 1;
+#elif _WIN32
+    DWORD dw;
+    int result;
+
+    dw = GetFileAttributesA(name);
+    if (dw == -1L)
+        result = 0;
+    else if (dw & FILE_ATTRIBUTE_DIRECTORY)
+        result = 2;
+    else
+        result = 1;
+    return result;
+#else
+    assert(0);
+#endif
+}
+
+bool FileName::ensurePathExists(const char *path)
+{
+    //printf("FileName::ensurePathExists(%s)\n", path ? path : "");
+    if (path && *path)
+    {
+        if (!exists(path))
+        {
+            const char *p = FileName::path(path);
+            if (*p)
+            {
+#if _WIN32
+                size_t len = strlen(path);
+                if ((len > 2 && p[-1] == ':' && strcmp(path + 2, p) == 0) ||
+                    len == strlen(p))
+                {   mem.xfree((void *)p);
+                    return 0;
+                }
+#endif
+                bool r = ensurePathExists(p);
+                mem.xfree((void *)p);
+                if (r)
+                    return r;
+            }
+#if _WIN32
+            char sep = '\\';
+#elif POSIX
+            char sep = '/';
+#endif
+            if (path[strlen(path) - 1] != sep)
+            {
+                //printf("mkdir(%s)\n", path);
+#if _WIN32
+                int r = _mkdir(path);
+#endif
+#if POSIX
+                int r = mkdir(path, (7 << 6) | (7 << 3) | 7);
+#endif
+                if (r)
+                {
+                    /* Don't error out if another instance of dmd just created
+                     * this directory
+                     */
+                    if (errno != EEXIST)
+                        return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+/******************************************
+ * Return canonical version of name in a malloc'd buffer.
+ * This code is high risk.
+ */
+const char *FileName::canonicalName(const char *name)
+{
+#if POSIX
+    // NULL destination buffer is allowed and preferred
+    return realpath(name, NULL);
+#elif _WIN32
+    /* Apparently, there is no good way to do this on Windows.
+     * GetFullPathName isn't it, but use it anyway.
+     */
+    DWORD result = GetFullPathNameA(name, 0, NULL, NULL);
+    if (result)
+    {
+        char *buf = (char *)malloc(result);
+        result = GetFullPathNameA(name, result, buf, NULL);
+        if (result == 0)
+        {
+            ::free(buf);
+            return NULL;
+        }
+        return buf;
+    }
+    return NULL;
+#else
+    assert(0);
+    return NULL;
+#endif
+}
+
+/********************************
+ * Free memory allocated by FileName routines
+ */
+void FileName::free(const char *str)
+{
+    if (str)
+    {   assert(str[0] != (char)0xAB);
+        memset((void *)str, 0xAB, strlen(str) + 1);     // stomp
+    }
+    mem.xfree((void *)str);
+}
+
+const char *FileName::toChars() const
+{
+    return str;
+}
diff --git a/gcc/d/dfrontend/filename.h b/gcc/d/dfrontend/filename.h
new file mode 100644
index 00000000000..829996ddd8c
--- /dev/null
+++ b/gcc/d/dfrontend/filename.h
@@ -0,0 +1,59 @@
+
+/* Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/dlang/dmd/blob/master/src/root/filename.h
+ */
+
+#ifndef FILENAME_H
+#define FILENAME_H
+
+#if __DMC__
+#pragma once
+#endif
+
+#include "array.h"
+
+class RootObject;
+
+template <typename TYPE> struct Array;
+typedef Array<const char *> Strings;
+
+struct FileName
+{
+    const char *str;
+    FileName(const char *str);
+    bool equals(RootObject *obj);
+    static bool equals(const char *name1, const char *name2);
+    int compare(RootObject *obj);
+    static int compare(const char *name1, const char *name2);
+    static bool absolute(const char *name);
+    static const char *ext(const char *);
+    const char *ext();
+    static const char *removeExt(const char *str);
+    static const char *name(const char *);
+    const char *name();
+    static const char *path(const char *);
+    static const char *replaceName(const char *path, const char *name);
+
+    static const char *combine(const char *path, const char *name);
+    static Strings *splitPath(const char *path);
+    static const char *defaultExt(const char *name, const char *ext);
+    static const char *forceExt(const char *name, const char *ext);
+    static bool equalsExt(const char *name, const char *ext);
+
+    bool equalsExt(const char *ext);
+
+    static const char *searchPath(Strings *path, const char *name, bool cwd);
+    static const char *safeSearchPath(Strings *path, const char *name);
+    static int exists(const char *name);
+    static bool ensurePathExists(const char *path);
+    static const char *canonicalName(const char *name);
+
+    static void free(const char *str);
+    const char *toChars() const;
+};
+
+#endif
diff --git a/gcc/d/dfrontend/func.c b/gcc/d/dfrontend/func.c
new file mode 100644
index 00000000000..47c9764adfb
--- /dev/null
+++ b/gcc/d/dfrontend/func.c
@@ -0,0 +1,5667 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/func.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "init.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "expression.h"
+#include "scope.h"
+#include "mtype.h"
+#include "aggregate.h"
+#include "identifier.h"
+#include "id.h"
+#include "module.h"
+#include "statement.h"
+#include "template.h"
+#include "hdrgen.h"
+#include "target.h"
+#include "parse.h"
+#include "rmem.h"
+#include "visitor.h"
+#include "objc.h"
+
+Expression *addInvariant(Loc loc, Scope *sc, AggregateDeclaration *ad, VarDeclaration *vthis, bool direct);
+bool checkEscape(Scope *sc, Expression *e, bool gag);
+bool checkEscapeRef(Scope *sc, Expression *e, bool gag);
+bool checkNestedRef(Dsymbol *s, Dsymbol *p);
+Statement *semantic(Statement *s, Scope *sc);
+void semantic(Catch *c, Scope *sc);
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+Expression *semantic(Expression *e, Scope *sc);
+int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow);
+
+void genCmain(Scope *sc);
+RET retStyle(TypeFunction *tf);
+void MODtoBuffer(OutBuffer *buf, MOD mod);
+char *MODtoChars(MOD mod);
+bool MODimplicitConv(MOD modfrom, MOD modto);
+MATCH MODmethodConv(MOD modfrom, MOD modto);
+void allocFieldinit(Scope *sc, size_t dim);
+void freeFieldinit(Scope *sc);
+Objc *objc();
+
+
+/* A visitor to walk entire statements and provides ability to replace any sub-statements.
+ */
+class StatementRewriteWalker : public Visitor
+{
+    /* Point the currently visited statement.
+     * By using replaceCurrent() method, you can replace AST during walking.
+     */
+    Statement **ps;
+public:
+    void visitStmt(Statement *&s) { ps = &s; s->accept(this); }
+    void replaceCurrent(Statement *s) { *ps = s; }
+
+    void visit(ErrorStatement *s) {  }
+    void visit(PeelStatement *s)
+    {
+        if (s->s)
+            visitStmt(s->s);
+    }
+    void visit(ExpStatement *s) {  }
+    void visit(DtorExpStatement *s) {  }
+    void visit(CompileStatement *s) {  }
+    void visit(CompoundStatement *s)
+    {
+        if (s->statements && s->statements->dim)
+        {
+            for (size_t i = 0; i < s->statements->dim; i++)
+            {
+                if ((*s->statements)[i])
+                    visitStmt((*s->statements)[i]);
+            }
+        }
+    }
+    void visit(CompoundDeclarationStatement *s) { visit((CompoundStatement *)s); }
+    void visit(UnrolledLoopStatement *s)
+    {
+        if (s->statements && s->statements->dim)
+        {
+            for (size_t i = 0; i < s->statements->dim; i++)
+            {
+                if ((*s->statements)[i])
+                    visitStmt((*s->statements)[i]);
+            }
+        }
+    }
+    void visit(ScopeStatement *s)
+    {
+        if (s->statement)
+            visitStmt(s->statement);
+    }
+    void visit(WhileStatement *s)
+    {
+        if (s->_body)
+            visitStmt(s->_body);
+    }
+    void visit(DoStatement *s)
+    {
+        if (s->_body)
+            visitStmt(s->_body);
+    }
+    void visit(ForStatement *s)
+    {
+        if (s->_init)
+            visitStmt(s->_init);
+        if (s->_body)
+            visitStmt(s->_body);
+    }
+    void visit(ForeachStatement *s)
+    {
+        if (s->_body)
+            visitStmt(s->_body);
+    }
+    void visit(ForeachRangeStatement *s)
+    {
+        if (s->_body)
+            visitStmt(s->_body);
+    }
+    void visit(IfStatement *s)
+    {
+        if (s->ifbody)
+            visitStmt(s->ifbody);
+        if (s->elsebody)
+            visitStmt(s->elsebody);
+    }
+    void visit(ConditionalStatement *s) {  }
+    void visit(PragmaStatement *s) {  }
+    void visit(StaticAssertStatement *s) {  }
+    void visit(SwitchStatement *s)
+    {
+        if (s->_body)
+            visitStmt(s->_body);
+    }
+    void visit(CaseStatement *s)
+    {
+        if (s->statement)
+            visitStmt(s->statement);
+    }
+    void visit(CaseRangeStatement *s)
+    {
+        if (s->statement)
+            visitStmt(s->statement);
+    }
+    void visit(DefaultStatement *s)
+    {
+        if (s->statement)
+            visitStmt(s->statement);
+    }
+    void visit(GotoDefaultStatement *s) {  }
+    void visit(GotoCaseStatement *s) {  }
+    void visit(SwitchErrorStatement *s) {  }
+    void visit(ReturnStatement *s) {  }
+    void visit(BreakStatement *s) {  }
+    void visit(ContinueStatement *s) {  }
+    void visit(SynchronizedStatement *s)
+    {
+        if (s->_body)
+            visitStmt(s->_body);
+    }
+    void visit(WithStatement *s)
+    {
+        if (s->_body)
+            visitStmt(s->_body);
+    }
+    void visit(TryCatchStatement *s)
+    {
+        if (s->_body)
+            visitStmt(s->_body);
+        if (s->catches && s->catches->dim)
+        {
+            for (size_t i = 0; i < s->catches->dim; i++)
+            {
+                Catch *c = (*s->catches)[i];
+                if (c && c->handler)
+                    visitStmt(c->handler);
+            }
+        }
+    }
+    void visit(TryFinallyStatement *s)
+    {
+        if (s->_body)
+            visitStmt(s->_body);
+        if (s->finalbody)
+            visitStmt(s->finalbody);
+    }
+    void visit(OnScopeStatement *s) {  }
+    void visit(ThrowStatement *s) {  }
+    void visit(DebugStatement *s)
+    {
+        if (s->statement)
+            visitStmt(s->statement);
+    }
+    void visit(GotoStatement *s) {  }
+    void visit(LabelStatement *s)
+    {
+        if (s->statement)
+            visitStmt(s->statement);
+    }
+    void visit(AsmStatement *s) {  }
+#ifdef IN_GCC
+    void visit(ExtAsmStatement *s) {  }
+#endif
+    void visit(ImportStatement *s) {  }
+};
+
+/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
+ */
+class NrvoWalker : public StatementRewriteWalker
+{
+public:
+    FuncDeclaration *fd;
+    Scope *sc;
+
+    void visit(ReturnStatement *s)
+    {
+        // See if all returns are instead to be replaced with a goto returnLabel;
+        if (fd->returnLabel)
+        {
+            /* Rewrite:
+             *  return exp;
+             * as:
+             *  vresult = exp; goto Lresult;
+             */
+            GotoStatement *gs = new GotoStatement(s->loc, Id::returnLabel);
+            gs->label = fd->returnLabel;
+
+            Statement *s1 = gs;
+            if (s->exp)
+                s1 = new CompoundStatement(s->loc, new ExpStatement(s->loc, s->exp), gs);
+
+            replaceCurrent(s1);
+        }
+    }
+    void visit(TryFinallyStatement *s)
+    {
+        DtorExpStatement *des;
+        if (fd->nrvo_can &&
+            s->finalbody && (des = s->finalbody->isDtorExpStatement()) != NULL &&
+            fd->nrvo_var == des->var)
+        {
+            /* Normally local variable dtors are called regardless exceptions.
+             * But for nrvo_var, its dtor should be called only when exception is thrown.
+             *
+             * Rewrite:
+             *      try { s->body; } finally { nrvo_var->edtor; }
+             *      // equivalent with:
+             *      //    s->body; scope(exit) nrvo_var->edtor;
+             * as:
+             *      try { s->body; } catch(__o) { nrvo_var->edtor; throw __o; }
+             *      // equivalent with:
+             *      //    s->body; scope(failure) nrvo_var->edtor;
+             */
+            Statement *sexception = new DtorExpStatement(Loc(), fd->nrvo_var->edtor, fd->nrvo_var);
+            Identifier *id = Identifier::generateId("__o");
+
+            Statement *handler = new PeelStatement(sexception);
+            if (blockExit(sexception, fd, false) & BEfallthru)
+            {
+                ThrowStatement *ts = new ThrowStatement(Loc(), new IdentifierExp(Loc(), id));
+                ts->internalThrow = true;
+                handler = new CompoundStatement(Loc(), handler, ts);
+            }
+
+            Catches *catches = new Catches();
+            Catch *ctch = new Catch(Loc(), NULL, id, handler);
+            ctch->internalCatch = true;
+            ::semantic(ctch, sc);     // Run semantic to resolve identifier '__o'
+            catches->push(ctch);
+
+            Statement *s2 = new TryCatchStatement(Loc(), s->_body, catches);
+            replaceCurrent(s2);
+            s2->accept(this);
+        }
+        else
+            StatementRewriteWalker::visit(s);
+    }
+};
+
+/********************************* FuncDeclaration ****************************/
+
+FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type)
+    : Declaration(id)
+{
+    //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type);
+    //printf("storage_class = x%x\n", storage_class);
+    this->storage_class = storage_class;
+    this->type = type;
+    if (type)
+    {
+        // Normalize storage_class, because function-type related attributes
+        // are already set in the 'type' in parsing phase.
+        this->storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR);
+    }
+    this->loc = loc;
+    this->endloc = endloc;
+    fthrows = NULL;
+    frequire = NULL;
+    fdrequire = NULL;
+    fdensure = NULL;
+    mangleString = NULL;
+    outId = NULL;
+    vresult = NULL;
+    returnLabel = NULL;
+    fensure = NULL;
+    fbody = NULL;
+    localsymtab = NULL;
+    vthis = NULL;
+    v_arguments = NULL;
+    v_argptr = NULL;
+    parameters = NULL;
+    labtab = NULL;
+    overnext = NULL;
+    overnext0 = NULL;
+    vtblIndex = -1;
+    hasReturnExp = 0;
+    naked = false;
+    generated = false;
+    inlineStatusExp = ILSuninitialized;
+    inlineStatusStmt = ILSuninitialized;
+    inlining = PINLINEdefault;
+    inlineNest = 0;
+    ctfeCode = NULL;
+    isArrayOp = 0;
+    semantic3Errors = false;
+    fes = NULL;
+    interfaceVirtual = NULL;
+    introducing = 0;
+    tintro = NULL;
+    /* The type given for "infer the return type" is a TypeFunction with
+     * NULL for the return type.
+     */
+    inferRetType = (type && type->nextOf() == NULL);
+    storage_class2 = 0;
+    hasReturnExp = 0;
+    nrvo_can = 1;
+    nrvo_var = NULL;
+    shidden = NULL;
+    builtin = BUILTINunknown;
+    tookAddressOf = 0;
+    requiresClosure = false;
+    inlinedNestedCallees = NULL;
+    flags = 0;
+    returns = NULL;
+    gotos = NULL;
+    selector = NULL;
+}
+
+FuncDeclaration *FuncDeclaration::create(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type)
+{
+    return new FuncDeclaration(loc, endloc, id, storage_class, type);
+}
+
+Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
+    FuncDeclaration *f =
+        s ? (FuncDeclaration *)s
+          : new FuncDeclaration(loc, endloc, ident, storage_class, type->syntaxCopy());
+    f->outId = outId;
+    f->frequire = frequire ? frequire->syntaxCopy() : NULL;
+    f->fensure  = fensure  ? fensure->syntaxCopy()  : NULL;
+    f->fbody    = fbody    ? fbody->syntaxCopy()    : NULL;
+    assert(!fthrows); // deprecated
+    return f;
+}
+
+/**********************************
+ * Decide if attributes for this function can be inferred from examining
+ * the function body.
+ * Returns:
+ *  true if can
+ */
+static bool canInferAttributes(FuncDeclaration *fd, Scope *sc)
+{
+    if (!fd->fbody)
+        return false;
+
+    if (fd->isVirtualMethod())
+        return false;               // since they may be overridden
+
+    if (sc->func &&
+        /********** this is for backwards compatibility for the moment ********/
+        (!fd->isMember() || sc->func->isSafeBypassingInference() && !fd->isInstantiated()))
+        return true;
+
+    if (fd->isFuncLiteralDeclaration() ||               // externs are not possible with literals
+        (fd->storage_class & STCinference) ||           // do attribute inference
+        (fd->inferRetType && !fd->isCtorDeclaration()))
+        return true;
+
+    if (fd->isInstantiated())
+    {
+        TemplateInstance *ti = fd->parent->isTemplateInstance();
+        if (ti == NULL || ti->isTemplateMixin() || ti->tempdecl->ident == fd->ident)
+            return true;
+    }
+
+    return false;
+}
+
+/*****************************************
+ * Initialize for inferring the attributes of this function.
+ */
+static void initInferAttributes(FuncDeclaration *fd)
+{
+    assert(fd->type->ty == Tfunction);
+    TypeFunction *tf = (TypeFunction *)fd->type;
+    if (tf->purity == PUREimpure) // purity not specified
+        fd->flags |= FUNCFLAGpurityInprocess;
+
+    if (tf->trust == TRUSTdefault)
+        fd->flags |= FUNCFLAGsafetyInprocess;
+
+    if (!tf->isnothrow)
+        fd->flags |= FUNCFLAGnothrowInprocess;
+
+    if (!tf->isnogc)
+        fd->flags |= FUNCFLAGnogcInprocess;
+
+    if (!fd->isVirtual() || fd->introducing)
+        fd->flags |= FUNCFLAGreturnInprocess;
+}
+
+// Do the semantic analysis on the external interface to the function.
+
+void FuncDeclaration::semantic(Scope *sc)
+{
+    TypeFunction *f;
+    AggregateDeclaration *ad;
+    InterfaceDeclaration *id;
+
+#if 0
+    printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage);
+    if (isFuncLiteralDeclaration())
+        printf("\tFuncLiteralDeclaration()\n");
+    printf("sc->parent = %s, parent = %s\n", sc->parent->toChars(), parent ? parent->toChars() : "");
+    printf("type: %p, %s\n", type, type->toChars());
+#endif
+
+    if (semanticRun != PASSinit && isFuncLiteralDeclaration())
+    {
+        /* Member functions that have return types that are
+         * forward references can have semantic() run more than
+         * once on them.
+         * See test\interface2.d, test20
+         */
+        return;
+    }
+
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    assert(semanticRun <= PASSsemantic);
+    semanticRun = PASSsemantic;
+
+    if (_scope)
+    {
+        sc = _scope;
+        _scope = NULL;
+    }
+
+    parent = sc->parent;
+    Dsymbol *parent = toParent();
+
+    foverrides.setDim(0);       // reset in case semantic() is being retried for this function
+
+    storage_class |= sc->stc & ~STCref;
+    ad = isThis();
+    if (ad)
+    {
+        storage_class |= ad->storage_class & (STC_TYPECTOR | STCsynchronized);
+
+        if (StructDeclaration *sd = ad->isStructDeclaration())
+            sd->makeNested();
+    }
+    if (sc->func)
+        storage_class |= sc->func->storage_class & STCdisable;
+    // Remove prefix storage classes silently.
+    if ((storage_class & STC_TYPECTOR) && !(ad || isNested()))
+        storage_class &= ~STC_TYPECTOR;
+
+    //printf("function storage_class = x%llx, sc->stc = x%llx, %x\n", storage_class, sc->stc, Declaration::isFinal());
+
+    FuncLiteralDeclaration *fld = isFuncLiteralDeclaration();
+    if (fld && fld->treq)
+    {
+        Type *treq = fld->treq;
+        assert(treq->nextOf()->ty == Tfunction);
+        if (treq->ty == Tdelegate)
+            fld->tok = TOKdelegate;
+        else if (treq->ty == Tpointer && treq->nextOf()->ty == Tfunction)
+            fld->tok = TOKfunction;
+        else
+            assert(0);
+        linkage = ((TypeFunction *)treq->nextOf())->linkage;
+    }
+    else
+        linkage = sc->linkage;
+    inlining = sc->inlining;
+    protection = sc->protection;
+    userAttribDecl = sc->userAttribDecl;
+
+    if (!originalType)
+        originalType = type->syntaxCopy();
+    if (!type->deco)
+    {
+        sc = sc->push();
+        sc->stc |= storage_class & (STCdisable | STCdeprecated);  // forward to function type
+        TypeFunction *tf = (TypeFunction *)type;
+
+        if (sc->func)
+        {
+            /* If the nesting parent is pure without inference,
+             * then this function defaults to pure too.
+             *
+             *  auto foo() pure {
+             *    auto bar() {}     // become a weak purity funciton
+             *    class C {         // nested class
+             *      auto baz() {}   // become a weak purity funciton
+             *    }
+             *
+             *    static auto boo() {}   // typed as impure
+             *    // Even though, boo cannot call any impure functions.
+             *    // See also Expression::checkPurity().
+             *  }
+             */
+            if (tf->purity == PUREimpure && (isNested() || isThis()))
+            {
+                FuncDeclaration *fd = NULL;
+                for (Dsymbol *p = toParent2(); p; p = p->toParent2())
+                {
+                    if (AggregateDeclaration *adx = p->isAggregateDeclaration())
+                    {
+                        if (adx->isNested())
+                            continue;
+                        break;
+                    }
+                    if ((fd = p->isFuncDeclaration()) != NULL)
+                        break;
+                }
+
+                /* If the parent's purity is inferred, then this function's purity needs
+                 * to be inferred first.
+                 */
+                if (fd && fd->isPureBypassingInference() >= PUREweak &&
+                    !isInstantiated())
+                {
+                    tf->purity = PUREfwdref;            // default to pure
+                }
+            }
+        }
+
+        if (tf->isref)      sc->stc |= STCref;
+        if (tf->isscope)    sc->stc |= STCscope;
+        if (tf->isnothrow)  sc->stc |= STCnothrow;
+        if (tf->isnogc)     sc->stc |= STCnogc;
+        if (tf->isproperty) sc->stc |= STCproperty;
+        if (tf->purity == PUREfwdref)   sc->stc |= STCpure;
+        if (tf->trust != TRUSTdefault)
+            sc->stc &= ~(STCsafe | STCsystem | STCtrusted);
+        if (tf->trust == TRUSTsafe)     sc->stc |= STCsafe;
+        if (tf->trust == TRUSTsystem)   sc->stc |= STCsystem;
+        if (tf->trust == TRUSTtrusted)  sc->stc |= STCtrusted;
+
+        if (isCtorDeclaration())
+        {
+            sc->flags |= SCOPEctor;
+
+            Type *tret = ad->handleType();
+            assert(tret);
+            tret = tret->addStorageClass(storage_class | sc->stc);
+            tret = tret->addMod(type->mod);
+            tf->next = tret;
+
+            if (ad->isStructDeclaration())
+                sc->stc |= STCref;
+        }
+
+        // 'return' on a non-static class member function implies 'scope' as well
+        if (ad && ad->isClassDeclaration() && (tf->isreturn || sc->stc & STCreturn) && !(sc->stc & STCstatic))
+            sc->stc |= STCscope;
+
+        sc->linkage = linkage;
+
+        if (!tf->isNaked() && !(isThis() || isNested()))
+        {
+            OutBuffer buf;
+            MODtoBuffer(&buf, tf->mod);
+            error("without 'this' cannot be %s", buf.peekString());
+            tf->mod = 0;    // remove qualifiers
+        }
+
+        /* Apply const, immutable, wild and shared storage class
+         * to the function type. Do this before type semantic.
+         */
+        StorageClass stc = storage_class;
+        if (type->isImmutable())
+            stc |= STCimmutable;
+        if (type->isConst())
+            stc |= STCconst;
+        if (type->isShared() || storage_class & STCsynchronized)
+            stc |= STCshared;
+        if (type->isWild())
+            stc |= STCwild;
+        switch (stc & STC_TYPECTOR)
+        {
+            case STCimmutable:
+            case STCimmutable | STCconst:
+            case STCimmutable | STCwild:
+            case STCimmutable | STCwild | STCconst:
+            case STCimmutable | STCshared:
+            case STCimmutable | STCshared | STCconst:
+            case STCimmutable | STCshared | STCwild:
+            case STCimmutable | STCshared | STCwild | STCconst:
+                // Don't use immutableOf(), as that will do a merge()
+                type = type->makeImmutable();
+                break;
+
+            case STCconst:
+                type = type->makeConst();
+                break;
+
+            case STCwild:
+                type = type->makeWild();
+                break;
+
+            case STCwild | STCconst:
+                type = type->makeWildConst();
+                break;
+
+            case STCshared:
+                type = type->makeShared();
+                break;
+
+            case STCshared | STCconst:
+                type = type->makeSharedConst();
+                break;
+
+            case STCshared | STCwild:
+                type = type->makeSharedWild();
+                break;
+
+            case STCshared | STCwild | STCconst:
+                type = type->makeSharedWildConst();
+                break;
+
+            case 0:
+                break;
+
+            default:
+                assert(0);
+        }
+
+        type = type->semantic(loc, sc);
+        sc = sc->pop();
+    }
+    if (type->ty != Tfunction)
+    {
+        if (type->ty != Terror)
+        {
+            error("%s must be a function instead of %s", toChars(), type->toChars());
+            type = Type::terror;
+        }
+        errors = true;
+        return;
+    }
+    else
+    {
+        // Merge back function attributes into 'originalType'.
+        // It's used for mangling, ddoc, and json output.
+        TypeFunction *tfo = (TypeFunction *)originalType;
+        TypeFunction *tfx = (TypeFunction *)type;
+        tfo->mod        = tfx->mod;
+        tfo->isscope    = tfx->isscope;
+        tfo->isscopeinferred = tfx->isscopeinferred;
+        tfo->isref      = tfx->isref;
+        tfo->isnothrow  = tfx->isnothrow;
+        tfo->isnogc     = tfx->isnogc;
+        tfo->isproperty = tfx->isproperty;
+        tfo->purity     = tfx->purity;
+        tfo->trust      = tfx->trust;
+
+        storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR);
+    }
+
+    f = (TypeFunction *)type;
+    size_t nparams = Parameter::dim(f->parameters);
+
+    if ((storage_class & STCauto) && !f->isref && !inferRetType)
+        error("storage class 'auto' has no effect if return type is not inferred");
+    /* Functions can only be 'scope' if they have a 'this'
+     */
+    if (f->isscope && !isNested() && !ad)
+    {
+        error("functions cannot be scope");
+    }
+
+    if (f->isreturn && !needThis() && !isNested())
+    {
+        /* Non-static nested functions have a hidden 'this' pointer to which
+         * the 'return' applies
+         */
+        error("static member has no 'this' to which 'return' can apply");
+    }
+
+    if (isAbstract() && !isVirtual())
+    {
+        const char *sfunc;
+        if (isStatic())
+            sfunc = "static";
+        else if (protection.kind == PROTprivate || protection.kind == PROTpackage)
+            sfunc = protectionToChars(protection.kind);
+        else
+            sfunc = "non-virtual";
+        error("%s functions cannot be abstract", sfunc);
+    }
+
+    if (isOverride() && !isVirtual())
+    {
+        PROTKIND kind = prot().kind;
+        if ((kind == PROTprivate || kind == PROTpackage) && isMember())
+            error("%s method is not virtual and cannot override", protectionToChars(kind));
+        else
+            error("cannot override a non-virtual function");
+    }
+
+    if (isAbstract() && isFinalFunc())
+        error("cannot be both final and abstract");
+#if 0
+    if (isAbstract() && fbody)
+        error("abstract functions cannot have bodies");
+#endif
+
+#if 0
+    if (isStaticConstructor() || isStaticDestructor())
+    {
+        if (!isStatic() || type->nextOf()->ty != Tvoid)
+            error("static constructors / destructors must be static void");
+        if (f->arguments && f->arguments->dim)
+            error("static constructors / destructors must have empty parameter list");
+        // BUG: check for invalid storage classes
+    }
+#endif
+
+    id = parent->isInterfaceDeclaration();
+    if (id)
+    {
+        storage_class |= STCabstract;
+
+        if (isCtorDeclaration() ||
+            isPostBlitDeclaration() ||
+            isDtorDeclaration() ||
+            isInvariantDeclaration() ||
+            isNewDeclaration() || isDelete())
+            error("constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface %s", id->toChars());
+        if (fbody && isVirtual())
+            error("function body only allowed in final functions in interface %s", id->toChars());
+    }
+
+    if (UnionDeclaration *ud = parent->isUnionDeclaration())
+    {
+        if (isPostBlitDeclaration() ||
+            isDtorDeclaration() ||
+            isInvariantDeclaration())
+            error("destructors, postblits and invariants are not allowed in union %s", ud->toChars());
+    }
+
+    /* Contracts can only appear without a body when they are virtual interface functions
+     */
+    if (!fbody && (fensure || frequire) && !(id && isVirtual()))
+        error("in and out contracts require function body");
+
+    if (StructDeclaration *sd = parent->isStructDeclaration())
+    {
+        if (isCtorDeclaration())
+        {
+            goto Ldone;
+        }
+    }
+
+    if (ClassDeclaration *cd = parent->isClassDeclaration())
+    {
+        if (isCtorDeclaration())
+        {
+            goto Ldone;
+        }
+
+        if (storage_class & STCabstract)
+            cd->isabstract = ABSyes;
+
+        // if static function, do not put in vtbl[]
+        if (!isVirtual())
+        {
+            //printf("\tnot virtual\n");
+            goto Ldone;
+        }
+        // Suppress further errors if the return type is an error
+        if (type->nextOf() == Type::terror)
+            goto Ldone;
+
+        bool may_override = false;
+        for (size_t i = 0; i < cd->baseclasses->dim; i++)
+        {
+            BaseClass *b = (*cd->baseclasses)[i];
+            ClassDeclaration *cbd = b->type->toBasetype()->isClassHandle();
+            if (!cbd)
+                continue;
+            for (size_t j = 0; j < cbd->vtbl.dim; j++)
+            {
+                FuncDeclaration *f2 = cbd->vtbl[j]->isFuncDeclaration();
+                if (!f2 || f2->ident != ident)
+                    continue;
+                if (cbd->parent && cbd->parent->isTemplateInstance())
+                {
+                    if (!f2->functionSemantic())
+                        goto Ldone;
+                }
+                may_override = true;
+            }
+        }
+        if (may_override && type->nextOf() == NULL)
+        {
+            /* If same name function exists in base class but 'this' is auto return,
+             * cannot find index of base class's vtbl[] to override.
+             */
+            error("return type inference is not supported if may override base class function");
+        }
+
+        /* Find index of existing function in base class's vtbl[] to override
+         * (the index will be the same as in cd's current vtbl[])
+         */
+        int vi = cd->baseClass ? findVtblIndex((Dsymbols*)&cd->baseClass->vtbl, (int)cd->baseClass->vtbl.dim)
+                               : -1;
+
+        bool doesoverride = false;
+        switch (vi)
+        {
+            case -1:
+        Lintro:
+                /* Didn't find one, so
+                 * This is an 'introducing' function which gets a new
+                 * slot in the vtbl[].
+                 */
+
+                // Verify this doesn't override previous final function
+                if (cd->baseClass)
+                {
+                    Dsymbol *s = cd->baseClass->search(loc, ident);
+                    if (s)
+                    {
+                        FuncDeclaration *f2 = s->isFuncDeclaration();
+                        if (f2)
+                        {
+                            f2 = f2->overloadExactMatch(type);
+                            if (f2 && f2->isFinalFunc() && f2->prot().kind != PROTprivate)
+                                error("cannot override final function %s", f2->toPrettyChars());
+                        }
+                    }
+                }
+
+                /* These quirky conditions mimic what VC++ appears to do
+                 */
+                if (global.params.mscoff && cd->cpp &&
+                    cd->baseClass && cd->baseClass->vtbl.dim)
+                {
+                    /* if overriding an interface function, then this is not
+                     * introducing and don't put it in the class vtbl[]
+                     */
+                    interfaceVirtual = overrideInterface();
+                    if (interfaceVirtual)
+                    {
+                        //printf("\tinterface function %s\n", toChars());
+                        cd->vtblFinal.push(this);
+                        goto Linterfaces;
+                    }
+                }
+
+                if (isFinalFunc())
+                {
+                    // Don't check here, as it may override an interface function
+                    //if (isOverride())
+                        //error("is marked as override, but does not override any function");
+                    cd->vtblFinal.push(this);
+                }
+                else
+                {
+                    //printf("\tintroducing function %s\n", toChars());
+                    introducing = 1;
+                    if (cd->cpp && Target::reverseCppOverloads)
+                    {
+                        // with dmc, overloaded functions are grouped and in reverse order
+                        vtblIndex = (int)cd->vtbl.dim;
+                        for (size_t i = 0; i < cd->vtbl.dim; i++)
+                        {
+                            if (cd->vtbl[i]->ident == ident && cd->vtbl[i]->parent == parent)
+                            {
+                                vtblIndex = (int)i;
+                                break;
+                            }
+                        }
+                        // shift all existing functions back
+                        for (size_t i = cd->vtbl.dim; i > vtblIndex; i--)
+                        {
+                            FuncDeclaration *fd = cd->vtbl[i-1]->isFuncDeclaration();
+                            assert(fd);
+                            fd->vtblIndex++;
+                        }
+                        cd->vtbl.insert(vtblIndex, this);
+                    }
+                    else
+                    {
+                        // Append to end of vtbl[]
+                        vi = (int)cd->vtbl.dim;
+                        cd->vtbl.push(this);
+                        vtblIndex = vi;
+                    }
+                }
+                break;
+
+            case -2:
+                // can't determine because of forward references
+                return;
+
+            default:
+            {
+                FuncDeclaration *fdv = cd->baseClass->vtbl[vi]->isFuncDeclaration();
+                FuncDeclaration *fdc = cd->vtbl[vi]->isFuncDeclaration();
+                // This function is covariant with fdv
+
+                if (fdc == this)
+                {
+                    doesoverride = true;
+                    break;
+                }
+
+                if (fdc->toParent() == parent)
+                {
+                    //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc  = %p %s %s @ [%s]\n\tfdv  = %p %s %s @ [%s]\n",
+                    //        vi, this, this->toChars(), this->type->toChars(), this->loc.toChars(),
+                    //            fdc,  fdc ->toChars(), fdc ->type->toChars(), fdc ->loc.toChars(),
+                    //            fdv,  fdv ->toChars(), fdv ->type->toChars(), fdv ->loc.toChars());
+
+                    // fdc overrides fdv exactly, then this introduces new function.
+                    if (fdc->type->mod == fdv->type->mod && this->type->mod != fdv->type->mod)
+                        goto Lintro;
+                }
+
+                // This function overrides fdv
+                if (fdv->isFinalFunc())
+                    error("cannot override final function %s", fdv->toPrettyChars());
+
+                if (!isOverride())
+                {
+                    int vi2 = findVtblIndex(&cd->baseClass->vtbl, (int)cd->baseClass->vtbl.dim, false);
+                    if (vi2 < 0)
+                        // https://issues.dlang.org/show_bug.cgi?id=17349
+                        ::deprecation(loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute",
+                            fdv->toPrettyChars(), toPrettyChars());
+                    else
+                        ::error(loc, "implicitly overriding base class method %s with %s deprecated; add 'override' attribute",
+                            fdv->toPrettyChars(), toPrettyChars());
+                }
+
+                doesoverride = true;
+                if (fdc->toParent() == parent)
+                {
+                    // If both are mixins, or both are not, then error.
+                    // If either is not, the one that is not overrides the other.
+                    bool thismixin = this->parent->isClassDeclaration() != NULL;
+                    bool fdcmixin = fdc->parent->isClassDeclaration() != NULL;
+                    if (thismixin == fdcmixin)
+                    {
+                        error("multiple overrides of same function");
+                    }
+                    else if (!thismixin)    // fdc overrides fdv
+                    {
+                        // this doesn't override any function
+                        break;
+                    }
+                }
+                cd->vtbl[vi] = this;
+                vtblIndex = vi;
+
+                /* Remember which functions this overrides
+                 */
+                foverrides.push(fdv);
+
+                /* This works by whenever this function is called,
+                 * it actually returns tintro, which gets dynamically
+                 * cast to type. But we know that tintro is a base
+                 * of type, so we could optimize it by not doing a
+                 * dynamic cast, but just subtracting the isBaseOf()
+                 * offset if the value is != null.
+                 */
+
+                if (fdv->tintro)
+                    tintro = fdv->tintro;
+                else if (!type->equals(fdv->type))
+                {
+                    /* Only need to have a tintro if the vptr
+                     * offsets differ
+                     */
+                    int offset;
+                    if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset))
+                    {
+                        tintro = fdv->type;
+                    }
+                }
+                break;
+            }
+        }
+
+        /* Go through all the interface bases.
+         * If this function is covariant with any members of those interface
+         * functions, set the tintro.
+         */
+    Linterfaces:
+        for (size_t i = 0; i < cd->interfaces.length; i++)
+        {
+            BaseClass *b = cd->interfaces.ptr[i];
+            vi = findVtblIndex((Dsymbols *)&b->sym->vtbl, (int)b->sym->vtbl.dim);
+            switch (vi)
+            {
+                case -1:
+                    break;
+
+                case -2:
+                    // can't determine because of forward references
+                    return;
+
+                default:
+                {
+                    FuncDeclaration *fdv = (FuncDeclaration *)b->sym->vtbl[vi];
+                    Type *ti = NULL;
+
+                    /* Remember which functions this overrides
+                     */
+                    foverrides.push(fdv);
+
+                    /* Should we really require 'override' when implementing
+                     * an interface function?
+                     */
+                    //if (!isOverride())
+                        //warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars());
+
+                    if (fdv->tintro)
+                        ti = fdv->tintro;
+                    else if (!type->equals(fdv->type))
+                    {
+                        /* Only need to have a tintro if the vptr
+                         * offsets differ
+                         */
+                        int offset;
+                        if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset))
+                        {
+                            ti = fdv->type;
+                        }
+                    }
+                    if (ti)
+                    {
+                        if (tintro)
+                        {
+                            if (!tintro->nextOf()->equals(ti->nextOf()) &&
+                                !tintro->nextOf()->isBaseOf(ti->nextOf(), NULL) &&
+                                !ti->nextOf()->isBaseOf(tintro->nextOf(), NULL))
+                            {
+                                error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars());
+                            }
+                        }
+                        tintro = ti;
+                    }
+                    goto L2;
+                }
+            }
+        }
+
+        if (!doesoverride && isOverride() && (type->nextOf() || !may_override))
+        {
+            BaseClass *bc = NULL;
+            Dsymbol *s = NULL;
+            for (size_t i = 0; i < cd->baseclasses->dim; i++)
+            {
+                bc = (*cd->baseclasses)[i];
+                s = bc->sym->search_correct(ident);
+                if (s) break;
+            }
+
+            if (s)
+                error("does not override any function, did you mean to override '%s%s'?",
+                    bc->sym->isCPPclass() ? "extern (C++) " : "", s->toPrettyChars());
+            else
+                error("does not override any function");
+        }
+
+    L2: ;
+
+        /* Go through all the interface bases.
+         * Disallow overriding any final functions in the interface(s).
+         */
+        for (size_t i = 0; i < cd->interfaces.length; i++)
+        {
+            BaseClass *b = cd->interfaces.ptr[i];
+            if (b->sym)
+            {
+                Dsymbol *s = search_function(b->sym, ident);
+                if (s)
+                {
+                    FuncDeclaration *f2 = s->isFuncDeclaration();
+                    if (f2)
+                    {
+                        f2 = f2->overloadExactMatch(type);
+                        if (f2 && f2->isFinalFunc() && f2->prot().kind != PROTprivate)
+                            error("cannot override final function %s.%s", b->sym->toChars(), f2->toPrettyChars());
+                    }
+                }
+            }
+        }
+    }
+    else if (isOverride() && !parent->isTemplateInstance())
+        error("override only applies to class member functions");
+
+    // Reflect this->type to f because it could be changed by findVtblIndex
+    assert(type->ty == Tfunction);
+    f = (TypeFunction *)type;
+
+    /* Do not allow template instances to add virtual functions
+     * to a class.
+     */
+    if (isVirtual())
+    {
+        TemplateInstance *ti = parent->isTemplateInstance();
+        if (ti)
+        {
+            // Take care of nested templates
+            while (1)
+            {
+                TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance();
+                if (!ti2)
+                    break;
+                ti = ti2;
+            }
+
+            // If it's a member template
+            ClassDeclaration *cd = ti->tempdecl->isClassMember();
+            if (cd)
+            {
+                error("cannot use template to add virtual function to class '%s'", cd->toChars());
+            }
+        }
+    }
+
+    if (isMain())
+        checkDmain();       // Check main() parameters and return type
+
+Ldone:
+    /* Purity and safety can be inferred for some functions by examining
+     * the function body.
+     */
+    if (canInferAttributes(this, sc))
+        initInferAttributes(this);
+
+    Module::dprogress++;
+    semanticRun = PASSsemanticdone;
+
+    /* Save scope for possible later use (if we need the
+     * function internals)
+     */
+    _scope = sc->copy();
+    _scope->setNoFree();
+
+    static bool printedMain = false;  // semantic might run more than once
+    if (global.params.verbose && !printedMain)
+    {
+        const char *type = isMain() ? "main" : isWinMain() ? "winmain" : isDllMain() ? "dllmain" : (const char *)NULL;
+        Module *mod = sc->_module;
+
+        if (type && mod)
+        {
+            printedMain = true;
+            const char *name = FileName::searchPath(global.path, mod->srcfile->toChars(), true);
+            fprintf(global.stdmsg, "entry     %-10s\t%s\n", type, name);
+        }
+    }
+
+    if (fbody && isMain() && sc->_module->isRoot())
+        genCmain(sc);
+
+    assert(type->ty != Terror || errors);
+}
+
+void FuncDeclaration::semantic2(Scope *sc)
+{
+    if (semanticRun >= PASSsemantic2done)
+        return;
+    assert(semanticRun <= PASSsemantic2);
+    semanticRun = PASSsemantic2;
+
+    objc()->setSelector(this, sc);
+    objc()->validateSelector(this);
+
+    if (ClassDeclaration *cd = parent->isClassDeclaration())
+    {
+        objc()->checkLinkage(this);
+    }
+}
+
+/****************************************************
+ * Determine whether an 'out' contract is declared inside
+ * the given function or any of its overrides.
+ * Params:
+ *      fd = the function to search
+ * Returns:
+ *      true    found an 'out' contract
+ *      false   didn't find one
+ */
+static bool needsFensure(FuncDeclaration *fd)
+{
+    if (fd->fensure)
+        return true;
+
+    for (size_t i = 0; i < fd->foverrides.dim; i++)
+    {
+        FuncDeclaration *fdv = fd->foverrides[i];
+
+        if (fdv->fensure)
+            return true;
+
+        if (needsFensure(fdv))
+            return true;
+    }
+    return false;
+}
+
+// Do the semantic analysis on the internals of the function.
+
+void FuncDeclaration::semantic3(Scope *sc)
+{
+    VarDeclaration *argptr = NULL;
+    VarDeclaration *_arguments = NULL;
+
+    if (!parent)
+    {
+        if (global.errors)
+            return;
+        //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc);
+        assert(0);
+    }
+    if (isError(parent))
+        return;
+    //printf("FuncDeclaration::semantic3('%s.%s', %p, sc = %p, loc = %s)\n", parent->toChars(), toChars(), this, sc, loc.toChars());
+    //fflush(stdout);
+    //printf("storage class = x%x %x\n", sc->stc, storage_class);
+    //{ static int x; if (++x == 2) *(char*)0=0; }
+    //printf("\tlinkage = %d\n", sc->linkage);
+
+    if (ident == Id::assign && !inuse)
+    {
+        if (storage_class & STCinference)
+        {
+            /* Bugzilla 15044: For generated opAssign function, any errors
+             * from its body need to be gagged.
+             */
+            unsigned oldErrors = global.startGagging();
+            ++inuse;
+            semantic3(sc);
+            --inuse;
+            if (global.endGagging(oldErrors))   // if errors happened
+            {
+                // Disable generated opAssign, because some members forbid identity assignment.
+                storage_class |= STCdisable;
+                fbody = NULL;   // remove fbody which contains the error
+                semantic3Errors = false;
+            }
+            return;
+        }
+    }
+
+    //printf(" sc->incontract = %d\n", (sc->flags & SCOPEcontract));
+    if (semanticRun >= PASSsemantic3)
+        return;
+    semanticRun = PASSsemantic3;
+    semantic3Errors = false;
+
+    if (!type || type->ty != Tfunction)
+        return;
+    TypeFunction *f = (TypeFunction *)type;
+    if (!inferRetType && f->next->ty == Terror)
+        return;
+
+    if (!fbody && inferRetType && !f->next)
+    {
+        error("has no function body with return type inference");
+        return;
+    }
+
+    unsigned oldErrors = global.errors;
+
+    if (frequire)
+    {
+        for (size_t i = 0; i < foverrides.dim; i++)
+        {
+            FuncDeclaration *fdv = foverrides[i];
+
+            if (fdv->fbody && !fdv->frequire)
+            {
+                error("cannot have an in contract when overriden function %s does not have an in contract", fdv->toPrettyChars());
+                break;
+            }
+        }
+    }
+
+    // Remember whether we need to generate an 'out' contract.
+    bool needEnsure = needsFensure(this);
+
+    if (fbody || frequire || needEnsure)
+    {
+        /* Symbol table into which we place parameters and nested functions,
+         * solely to diagnose name collisions.
+         */
+        localsymtab = new DsymbolTable();
+
+        // Establish function scope
+        ScopeDsymbol *ss = new ScopeDsymbol();
+        // find enclosing scope symbol, might skip symbol-less CTFE and/or FuncExp scopes
+        for (Scope *scx = sc; ; scx = scx->enclosing)
+        {
+            if (scx->scopesym)
+            {
+                ss->parent = scx->scopesym;
+                break;
+            }
+        }
+        ss->loc = loc;
+        ss->endlinnum = endloc.linnum;
+        Scope *sc2 = sc->push(ss);
+        sc2->func = this;
+        sc2->parent = this;
+        sc2->callSuper = 0;
+        sc2->sbreak = NULL;
+        sc2->scontinue = NULL;
+        sc2->sw = NULL;
+        sc2->fes = fes;
+        sc2->linkage = LINKd;
+        sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract |
+                        STCdeprecated | STCoverride |
+                        STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref | STCreturn |
+                        STCproperty | STCnothrow | STCpure | STCsafe | STCtrusted | STCsystem);
+        sc2->protection = Prot(PROTpublic);
+        sc2->explicitProtection = 0;
+        sc2->aligndecl = NULL;
+        if (this->ident != Id::require && this->ident != Id::ensure)
+            sc2->flags = sc->flags & ~SCOPEcontract;
+        sc2->flags &= ~SCOPEcompile;
+        sc2->tf = NULL;
+        sc2->os = NULL;
+        sc2->noctor = 0;
+        sc2->userAttribDecl = NULL;
+        if (sc2->intypeof == 1) sc2->intypeof = 2;
+        sc2->fieldinit = NULL;
+        sc2->fieldinit_dim = 0;
+
+        /* Note: When a lambda is defined immediately under aggregate member
+         * scope, it should be contextless due to prevent interior pointers.
+         * e.g.
+         *      // dg points 'this' - it's interior pointer
+         *      class C { int x; void delegate() dg = (){ this.x = 1; }; }
+         *
+         * However, lambdas could be used inside typeof, in order to check
+         * some expressions varidity at compile time. For such case the lambda
+         * body can access aggregate instance members.
+         * e.g.
+         *      class C { int x; static assert(is(typeof({ this.x = 1; }))); }
+         *
+         * To properly accept it, mark these lambdas as member functions -
+         * isThis() returns true and isNested() returns false.
+         */
+        if (FuncLiteralDeclaration *fld = isFuncLiteralDeclaration())
+        {
+            if (AggregateDeclaration *ad = isMember2())
+            {
+                if (!sc->intypeof)
+                {
+                    if (fld->tok == TOKdelegate)
+                        error("cannot be %s members", ad->kind());
+                    else
+                        fld->tok = TOKfunction;
+                }
+                else
+                {
+                    if (fld->tok != TOKfunction)
+                        fld->tok = TOKdelegate;
+                }
+                assert(!isNested());
+            }
+        }
+
+        // Declare 'this'
+        AggregateDeclaration *ad = isThis();
+        vthis = declareThis(sc2, ad);
+        //printf("[%s] ad = %p vthis = %p\n", loc.toChars(), ad, vthis);
+        //if (vthis) printf("\tvthis->type = %s\n", vthis->type->toChars());
+
+        // Declare hidden variable _arguments[] and _argptr
+        if (f->varargs == 1)
+        {
+            if (f->linkage == LINKd)
+            {
+                // Declare _arguments[]
+                v_arguments = new VarDeclaration(Loc(), Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL);
+                v_arguments->storage_class |= STCtemp | STCparameter;
+                v_arguments->semantic(sc2);
+                sc2->insert(v_arguments);
+                v_arguments->parent = this;
+
+                //Type *t = Type::typeinfo->type->constOf()->arrayOf();
+                Type *t = Type::dtypeinfo->type->arrayOf();
+                _arguments = new VarDeclaration(Loc(), t, Id::_arguments, NULL);
+                _arguments->storage_class |= STCtemp;
+                _arguments->semantic(sc2);
+                sc2->insert(_arguments);
+                _arguments->parent = this;
+            }
+            if (f->linkage == LINKd || (f->parameters && Parameter::dim(f->parameters)))
+            {
+                // Declare _argptr
+                Type *t = Type::tvalist;
+                v_argptr = new VarDeclaration(Loc(), t, Id::_argptr, NULL);
+                v_argptr->storage_class |= STCtemp;
+                v_argptr->semantic(sc2);
+                sc2->insert(v_argptr);
+                v_argptr->parent = this;
+            }
+        }
+
+        /* Declare all the function parameters as variables
+         * and install them in parameters[]
+         */
+        size_t nparams = Parameter::dim(f->parameters);
+        if (nparams)
+        {
+            /* parameters[] has all the tuples removed, as the back end
+             * doesn't know about tuples
+             */
+            parameters = new VarDeclarations();
+            parameters->reserve(nparams);
+            for (size_t i = 0; i < nparams; i++)
+            {
+                Parameter *fparam = Parameter::getNth(f->parameters, i);
+                Identifier *id = fparam->ident;
+                StorageClass stc = 0;
+                if (!id)
+                {
+                    /* Generate identifier for un-named parameter,
+                     * because we need it later on.
+                     */
+                    fparam->ident = id = Identifier::generateId("_param_", i);
+                    stc |= STCtemp;
+                }
+                Type *vtype = fparam->type;
+                VarDeclaration *v = new VarDeclaration(loc, vtype, id, NULL);
+                //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars());
+                stc |= STCparameter;
+                if (f->varargs == 2 && i + 1 == nparams)
+                    stc |= STCvariadic;
+                if (flags & FUNCFLAGinferScope)
+                    stc |= STCmaybescope;
+                stc |= fparam->storageClass & (STCin | STCout | STCref | STCreturn | STCscope | STClazy | STCfinal | STC_TYPECTOR | STCnodtor);
+                v->storage_class = stc;
+                v->semantic(sc2);
+                if (!sc2->insert(v))
+                    error("parameter %s.%s is already defined", toChars(), v->toChars());
+                else
+                    parameters->push(v);
+                localsymtab->insert(v);
+                v->parent = this;
+            }
+        }
+
+        // Declare the tuple symbols and put them in the symbol table,
+        // but not in parameters[].
+        if (f->parameters)
+        {
+            for (size_t i = 0; i < f->parameters->dim; i++)
+            {
+                Parameter *fparam = (*f->parameters)[i];
+
+                if (!fparam->ident)
+                    continue;                   // never used, so ignore
+                if (fparam->type->ty == Ttuple)
+                {
+                    TypeTuple *t = (TypeTuple *)fparam->type;
+                    size_t dim = Parameter::dim(t->arguments);
+                    Objects *exps = new Objects();
+                    exps->setDim(dim);
+                    for (size_t j = 0; j < dim; j++)
+                    {
+                        Parameter *narg = Parameter::getNth(t->arguments, j);
+                        assert(narg->ident);
+                        VarDeclaration *v = sc2->search(Loc(), narg->ident, NULL)->isVarDeclaration();
+                        assert(v);
+                        Expression *e = new VarExp(v->loc, v);
+                        (*exps)[j] = e;
+                    }
+                    assert(fparam->ident);
+                    TupleDeclaration *v = new TupleDeclaration(loc, fparam->ident, exps);
+                    //printf("declaring tuple %s\n", v->toChars());
+                    v->isexp = true;
+                    if (!sc2->insert(v))
+                        error("parameter %s.%s is already defined", toChars(), v->toChars());
+                    localsymtab->insert(v);
+                    v->parent = this;
+                }
+            }
+        }
+
+        // Precondition invariant
+        Statement *fpreinv = NULL;
+        if (addPreInvariant())
+        {
+            Expression *e = addInvariant(loc, sc, ad, vthis, isDtorDeclaration() != NULL);
+            if (e)
+                fpreinv = new ExpStatement(Loc(), e);
+        }
+
+        // Postcondition invariant
+        Statement *fpostinv = NULL;
+        if (addPostInvariant())
+        {
+            Expression *e = addInvariant(loc, sc, ad, vthis, isCtorDeclaration() != NULL);
+            if (e)
+                fpostinv = new ExpStatement(Loc(), e);
+        }
+
+        Scope *scout = NULL;
+        if (needEnsure || addPostInvariant())
+        {
+            if ((needEnsure && global.params.useOut) || fpostinv)
+            {
+                returnLabel = new LabelDsymbol(Id::returnLabel);
+            }
+
+            // scope of out contract (need for vresult->semantic)
+            ScopeDsymbol *sym = new ScopeDsymbol();
+            sym->parent = sc2->scopesym;
+            sym->loc = loc;
+            sym->endlinnum = endloc.linnum;
+            scout = sc2->push(sym);
+        }
+
+        if (fbody)
+        {
+            ScopeDsymbol *sym = new ScopeDsymbol();
+            sym->parent = sc2->scopesym;
+            sym->loc = loc;
+            sym->endlinnum = endloc.linnum;
+            sc2 = sc2->push(sym);
+
+            AggregateDeclaration *ad2 = isMember2();
+
+            /* If this is a class constructor
+             */
+            if (ad2 && isCtorDeclaration())
+            {
+                allocFieldinit(sc2, ad2->fields.dim);
+                for (size_t i = 0; i < ad2->fields.dim; i++)
+                {
+                    VarDeclaration *v = ad2->fields[i];
+                    v->ctorinit = 0;
+                }
+            }
+
+            if (!inferRetType && retStyle(f) != RETstack)
+                nrvo_can = 0;
+
+            bool inferRef = (f->isref && (storage_class & STCauto));
+
+            fbody = ::semantic(fbody, sc2);
+            if (!fbody)
+                fbody = new CompoundStatement(Loc(), new Statements());
+
+            if (naked)
+            {
+                fpreinv = NULL;         // can't accommodate with no stack frame
+                fpostinv = NULL;
+            }
+
+            assert(type == f ||
+                   (type->ty == Tfunction &&
+                    f->purity == PUREimpure &&
+                    ((TypeFunction *)type)->purity >= PUREfwdref));
+            f = (TypeFunction *)type;
+
+            if (inferRetType)
+            {
+                // If no return type inferred yet, then infer a void
+                if (!f->next)
+                    f->next = Type::tvoid;
+                if (f->checkRetType(loc))
+                    fbody = new ErrorStatement();
+            }
+            if (global.params.vcomplex && f->next != NULL)
+                f->next->checkComplexTransition(loc);
+
+            if (returns && !fbody->isErrorStatement())
+            {
+                for (size_t i = 0; i < returns->dim; )
+                {
+                    Expression *exp = (*returns)[i]->exp;
+                    if (exp->op == TOKvar && ((VarExp *)exp)->var == vresult)
+                    {
+                        exp->type = f->next;
+                        // Remove `return vresult;` from returns
+                        returns->remove(i);
+                        continue;
+                    }
+                    if (inferRef && f->isref && !exp->type->constConv(f->next))     // Bugzilla 13336
+                        f->isref = false;
+                    i++;
+                }
+            }
+            if (f->isref)   // Function returns a reference
+            {
+                if (storage_class & STCauto)
+                    storage_class &= ~STCauto;
+            }
+            if (retStyle(f) != RETstack)
+                nrvo_can = 0;
+
+            if (fbody->isErrorStatement())
+                ;
+            else if (isStaticCtorDeclaration())
+            {
+                /* It's a static constructor. Ensure that all
+                 * ctor consts were initialized.
+                 */
+                ScopeDsymbol *pd = toParent()->isScopeDsymbol();
+                for (size_t i = 0; i < pd->members->dim; i++)
+                {
+                    Dsymbol *s = (*pd->members)[i];
+                    s->checkCtorConstInit();
+                }
+            }
+            else if (ad2 && isCtorDeclaration())
+            {
+                ClassDeclaration *cd = ad2->isClassDeclaration();
+
+                // Verify that all the ctorinit fields got initialized
+                if (!(sc2->callSuper & CSXthis_ctor))
+                {
+                    for (size_t i = 0; i < ad2->fields.dim; i++)
+                    {
+                        VarDeclaration *v = ad2->fields[i];
+                        if (v->isThisDeclaration())
+                            continue;
+                        if (v->ctorinit == 0)
+                        {
+                            /* Current bugs in the flow analysis:
+                             * 1. union members should not produce error messages even if
+                             *    not assigned to
+                             * 2. structs should recognize delegating opAssign calls as well
+                             *    as delegating calls to other constructors
+                             */
+                            if (v->isCtorinit() && !v->type->isMutable() && cd)
+                                error("missing initializer for %s field %s", MODtoChars(v->type->mod), v->toChars());
+                            else if (v->storage_class & STCnodefaultctor)
+                                ::error(loc, "field %s must be initialized in constructor", v->toChars());
+                            else if (v->type->needsNested())
+                                ::error(loc, "field %s must be initialized in constructor, because it is nested struct", v->toChars());
+                        }
+                        else
+                        {
+                            bool mustInit = (v->storage_class & STCnodefaultctor ||
+                                             v->type->needsNested());
+                            if (mustInit && !(sc2->fieldinit[i] & CSXthis_ctor))
+                            {
+                                error("field %s must be initialized but skipped", v->toChars());
+                            }
+                        }
+                    }
+                }
+                freeFieldinit(sc2);
+
+                if (cd &&
+                    !(sc2->callSuper & CSXany_ctor) &&
+                    cd->baseClass && cd->baseClass->ctor)
+                {
+                    sc2->callSuper = 0;
+
+                    // Insert implicit super() at start of fbody
+                    FuncDeclaration *fd = resolveFuncCall(Loc(), sc2, cd->baseClass->ctor, NULL, NULL, NULL, 1);
+                    if (!fd)
+                    {
+                        error("no match for implicit super() call in constructor");
+                    }
+                    else if (fd->storage_class & STCdisable)
+                    {
+                        error("cannot call super() implicitly because it is annotated with @disable");
+                    }
+                    else
+                    {
+                        Expression *e1 = new SuperExp(Loc());
+                        Expression *e = new CallExp(Loc(), e1);
+                        e = ::semantic(e, sc2);
+
+                        Statement *s = new ExpStatement(Loc(), e);
+                        fbody = new CompoundStatement(Loc(), s, fbody);
+                    }
+                }
+                //printf("callSuper = x%x\n", sc2->callSuper);
+            }
+
+            int blockexit = BEnone;
+            if (!fbody->isErrorStatement())
+            {
+                // Check for errors related to 'nothrow'.
+                unsigned int nothrowErrors = global.errors;
+                blockexit = blockExit(fbody, this, f->isnothrow);
+                if (f->isnothrow && (global.errors != nothrowErrors))
+                    ::error(loc, "nothrow %s '%s' may throw", kind(), toPrettyChars());
+                if (flags & FUNCFLAGnothrowInprocess)
+                {
+                    if (type == f) f = (TypeFunction *)f->copy();
+                    f->isnothrow = !(blockexit & BEthrow);
+                }
+            }
+
+            if (fbody->isErrorStatement())
+                ;
+            else if (ad2 && isCtorDeclaration())
+            {
+                /* Append:
+                 *  return this;
+                 * to function body
+                 */
+                if (blockexit & BEfallthru)
+                {
+                    Statement *s = new ReturnStatement(loc, NULL);
+                    s = ::semantic(s, sc2);
+                    fbody = new CompoundStatement(loc, fbody, s);
+                    hasReturnExp |= (hasReturnExp & 1 ? 16 : 1);
+                }
+            }
+            else if (fes)
+            {
+                // For foreach(){} body, append a return 0;
+                if (blockexit & BEfallthru)
+                {
+                    Expression *e = new IntegerExp(0);
+                    Statement *s = new ReturnStatement(Loc(), e);
+                    fbody = new CompoundStatement(Loc(), fbody, s);
+                    hasReturnExp |= (hasReturnExp & 1 ? 16 : 1);
+                }
+                assert(!returnLabel);
+            }
+            else
+            {
+                const bool inlineAsm = (hasReturnExp & 8) != 0;
+                if ((blockexit & BEfallthru) && f->next->ty != Tvoid && !inlineAsm)
+                {
+                    Expression *e;
+                    if (!hasReturnExp)
+                        error("has no return statement, but is expected to return a value of type %s", f->next->toChars());
+                    else
+                        error("no return exp; or assert(0); at end of function");
+                    if (global.params.useAssert &&
+                        !global.params.useInline)
+                    {
+                        /* Add an assert(0, msg); where the missing return
+                         * should be.
+                         */
+                        e = new AssertExp(
+                              endloc,
+                              new IntegerExp(0),
+                              new StringExp(loc, (char *)"missing return expression")
+                            );
+                    }
+                    else
+                        e = new HaltExp(endloc);
+                    e = new CommaExp(Loc(), e, f->next->defaultInit());
+                    e = ::semantic(e, sc2);
+                    Statement *s = new ExpStatement(Loc(), e);
+                    fbody = new CompoundStatement(Loc(), fbody, s);
+                }
+            }
+
+            if (returns && !fbody->isErrorStatement())
+            {
+                bool implicit0 = (f->next->ty == Tvoid && isMain());
+                Type *tret = implicit0 ? Type::tint32 : f->next;
+                assert(tret->ty != Tvoid);
+                if (vresult || returnLabel)
+                    buildResultVar(scout ? scout : sc2, tret);
+
+                /* Cannot move this loop into NrvoWalker, because
+                 * returns[i] may be in the nested delegate for foreach-body.
+                 */
+                for (size_t i = 0; i < returns->dim; i++)
+                {
+                    ReturnStatement *rs = (*returns)[i];
+                    Expression *exp = rs->exp;
+
+                    if (!exp->implicitConvTo(tret) &&
+                        parametersIntersect(exp->type))
+                    {
+                        if (exp->type->immutableOf()->implicitConvTo(tret))
+                            exp = exp->castTo(sc2, exp->type->immutableOf());
+                        else if (exp->type->wildOf()->implicitConvTo(tret))
+                            exp = exp->castTo(sc2, exp->type->wildOf());
+                    }
+                    exp = exp->implicitCastTo(sc2, tret);
+
+                    if (f->isref)
+                    {
+                        // Function returns a reference
+                        exp = exp->toLvalue(sc2, exp);
+                        checkEscapeRef(sc2, exp, false);
+                    }
+                    else
+                    {
+                        exp = exp->optimize(WANTvalue);
+
+                        /* Bugzilla 10789:
+                         * If NRVO is not possible, all returned lvalues should call their postblits.
+                         */
+                        if (!nrvo_can)
+                            exp = doCopyOrMove(sc2, exp);
+
+                        if (tret->hasPointers())
+                            checkEscape(sc2, exp, false);
+                    }
+
+                    exp = checkGC(sc2, exp);
+
+                    if (vresult)
+                    {
+                        // Create: return vresult = exp;
+                        exp = new BlitExp(rs->loc, vresult, exp);
+                        exp->type = vresult->type;
+
+                        if (rs->caseDim)
+                            exp = Expression::combine(exp, new IntegerExp(rs->caseDim));
+                    }
+                    else if (tintro && !tret->equals(tintro->nextOf()))
+                    {
+                        exp = exp->implicitCastTo(sc2, tintro->nextOf());
+                    }
+                    rs->exp = exp;
+                }
+            }
+            if (nrvo_var || returnLabel)
+            {
+                NrvoWalker nw;
+                nw.fd = this;
+                nw.sc = sc2;
+                nw.visitStmt(fbody);
+            }
+
+            sc2 = sc2->pop();
+        }
+
+        /* https://issues.dlang.org/show_bug.cgi?id=17502
+         * Wait until after the return type has been inferred before
+         * generating the contracts for this function, and merging contracts
+         * from overrides.
+         *
+         * This was originally at the end of the first semantic pass, but
+         * required a fix-up to be done here for the '__result' variable
+         * type of __ensure() inside auto functions, but this didn't work
+         * if the out parameter was implicit.
+         */
+        if (isVirtual())
+        {
+            /* Rewrite contracts as nested functions, then call them.
+             * Doing it as nested functions means that overriding functions
+             * can call them.
+             */
+            if (frequire)
+            {
+                /*   in { ... }
+                 * becomes:
+                 *   void __require() { ... }
+                 *   __require();
+                 */
+                Loc loc = frequire->loc;
+                TypeFunction *tf = new TypeFunction(NULL, Type::tvoid, 0, LINKd);
+                tf->isnothrow = f->isnothrow;
+                tf->isnogc = f->isnogc;
+                tf->purity = f->purity;
+                tf->trust = f->trust;
+                FuncDeclaration *fd = new FuncDeclaration(loc, loc,
+                                                          Id::require, STCundefined, tf);
+                fd->fbody = frequire;
+                Statement *s1 = new ExpStatement(loc, fd);
+                Expression *e = new CallExp(loc, new VarExp(loc, fd, false), (Expressions *)NULL);
+                Statement *s2 = new ExpStatement(loc, e);
+                frequire = new CompoundStatement(loc, s1, s2);
+                fdrequire = fd;
+            }
+
+            if (!outId && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid)
+                outId = Id::result; // provide a default
+
+            if (fensure)
+            {
+                /*   out (result) { ... }
+                 * becomes:
+                 *   void __ensure(ref tret result) { ... }
+                 *   __ensure(result);
+                 */
+                Loc loc = fensure->loc;
+                Parameters *fparams = new Parameters();
+                Parameter *p = NULL;
+                if (outId)
+                {
+                    p = new Parameter(STCref | STCconst, f->nextOf(), outId, NULL);
+                    fparams->push(p);
+                }
+                TypeFunction *tf = new TypeFunction(fparams, Type::tvoid, 0, LINKd);
+                tf->isnothrow = f->isnothrow;
+                tf->isnogc = f->isnogc;
+                tf->purity = f->purity;
+                tf->trust = f->trust;
+                FuncDeclaration *fd = new FuncDeclaration(loc, loc,
+                                                          Id::ensure, STCundefined, tf);
+                fd->fbody = fensure;
+                Statement *s1 = new ExpStatement(loc, fd);
+                Expression *eresult = NULL;
+                if (outId)
+                    eresult = new IdentifierExp(loc, outId);
+                Expression *e = new CallExp(loc, new VarExp(loc, fd, false), eresult);
+                Statement *s2 = new ExpStatement(loc, e);
+                fensure = new CompoundStatement(loc, s1, s2);
+                fdensure = fd;
+            }
+        }
+
+        frequire = mergeFrequire(frequire);
+        fensure = mergeFensure(fensure, outId);
+
+        Statement *freq = frequire;
+        Statement *fens = fensure;
+
+        /* Do the semantic analysis on the [in] preconditions and
+         * [out] postconditions.
+         */
+        if (freq)
+        {
+            /* frequire is composed of the [in] contracts
+             */
+            ScopeDsymbol *sym = new ScopeDsymbol();
+            sym->parent = sc2->scopesym;
+            sym->loc = loc;
+            sym->endlinnum = endloc.linnum;
+            sc2 = sc2->push(sym);
+            sc2->flags = (sc2->flags & ~SCOPEcontract) | SCOPErequire;
+
+            // BUG: need to error if accessing out parameters
+            // BUG: need to treat parameters as const
+            // BUG: need to disallow returns and throws
+            // BUG: verify that all in and ref parameters are read
+            freq = ::semantic(freq, sc2);
+            blockExit(freq, this, false);
+
+            sc2 = sc2->pop();
+
+            if (!global.params.useIn)
+                freq = NULL;
+        }
+
+        if (fens)
+        {
+            /* fensure is composed of the [out] contracts
+             */
+            if (f->next->ty == Tvoid && outId)
+                error("void functions have no result");
+
+            sc2 = scout;    //push
+            sc2->flags = (sc2->flags & ~SCOPEcontract) | SCOPEensure;
+
+            // BUG: need to treat parameters as const
+            // BUG: need to disallow returns and throws
+            if (fensure && f->next->ty != Tvoid)
+                buildResultVar(scout, f->next);
+
+            fens = ::semantic(fens, sc2);
+            blockExit(fens, this, false);
+
+            sc2 = sc2->pop();
+
+            if (!global.params.useOut)
+                fens = NULL;
+        }
+
+        if (fbody && fbody->isErrorStatement())
+            ;
+        else
+        {
+            Statements *a = new Statements();
+
+            // Merge in initialization of 'out' parameters
+            if (parameters)
+            {
+                for (size_t i = 0; i < parameters->dim; i++)
+                {
+                    VarDeclaration *v = (*parameters)[i];
+                    if (v->storage_class & STCout)
+                    {
+                        assert(v->_init);
+                        ExpInitializer *ie = v->_init->isExpInitializer();
+                        assert(ie);
+                        if (ie->exp->op == TOKconstruct)
+                            ie->exp->op = TOKassign; // construction occured in parameter processing
+                        a->push(new ExpStatement(Loc(), ie->exp));
+                    }
+                }
+            }
+
+            if (v_argptr)
+            {
+                // Handled in FuncDeclaration::toObjFile
+                v_argptr->_init = new VoidInitializer(loc);
+            }
+
+            if (_arguments)
+            {
+                /* Advance to elements[] member of TypeInfo_Tuple with:
+                 *  _arguments = v_arguments.elements;
+                 */
+                Expression *e = new VarExp(Loc(), v_arguments);
+                e = new DotIdExp(Loc(), e, Id::elements);
+                e = new ConstructExp(Loc(), _arguments, e);
+                e = ::semantic(e, sc2);
+
+                _arguments->_init = new ExpInitializer(Loc(), e);
+                DeclarationExp *de = new DeclarationExp(Loc(), _arguments);
+                a->push(new ExpStatement(Loc(), de));
+            }
+
+            // Merge contracts together with body into one compound statement
+
+            if (freq || fpreinv)
+            {
+                if (!freq)
+                    freq = fpreinv;
+                else if (fpreinv)
+                    freq = new CompoundStatement(Loc(), freq, fpreinv);
+
+                a->push(freq);
+            }
+
+            if (fbody)
+                a->push(fbody);
+
+            if (fens || fpostinv)
+            {
+                if (!fens)
+                    fens = fpostinv;
+                else if (fpostinv)
+                    fens = new CompoundStatement(Loc(), fpostinv, fens);
+
+                LabelStatement *ls = new LabelStatement(Loc(), Id::returnLabel, fens);
+                returnLabel->statement = ls;
+                a->push(returnLabel->statement);
+
+                if (f->next->ty != Tvoid && vresult)
+                {
+                    // Create: return vresult;
+                    Expression *e = new VarExp(Loc(), vresult);
+                    if (tintro)
+                    {
+                        e = e->implicitCastTo(sc, tintro->nextOf());
+                        e = ::semantic(e, sc);
+                    }
+                    ReturnStatement *s = new ReturnStatement(Loc(), e);
+                    a->push(s);
+                }
+            }
+            if (isMain() && f->next->ty == Tvoid)
+            {
+                // Add a return 0; statement
+                Statement *s = new ReturnStatement(Loc(), new IntegerExp(0));
+                a->push(s);
+            }
+
+            Statement *sbody = new CompoundStatement(Loc(), a);
+            /* Append destructor calls for parameters as finally blocks.
+             */
+            if (parameters)
+            {
+                for (size_t i = 0; i < parameters->dim; i++)
+                {
+                    VarDeclaration *v = (*parameters)[i];
+
+                    if (v->storage_class & (STCref | STCout | STClazy))
+                        continue;
+
+                    if (v->needsScopeDtor())
+                    {
+                        // same with ExpStatement.scopeCode()
+                        Statement *s = new DtorExpStatement(Loc(), v->edtor, v);
+                        v->storage_class |= STCnodtor;
+
+                        s = ::semantic(s, sc2);
+
+                        bool isnothrow = f->isnothrow & !(flags & FUNCFLAGnothrowInprocess);
+                        int blockexit = blockExit(s, this, isnothrow);
+                        if (f->isnothrow && isnothrow && blockexit & BEthrow)
+                            ::error(loc, "nothrow %s '%s' may throw", kind(), toPrettyChars());
+                        if (flags & FUNCFLAGnothrowInprocess && blockexit & BEthrow)
+                            f->isnothrow = false;
+                        if (blockExit(sbody, this, f->isnothrow) == BEfallthru)
+                            sbody = new CompoundStatement(Loc(), sbody, s);
+                        else
+                            sbody = new TryFinallyStatement(Loc(), sbody, s);
+                    }
+                }
+            }
+            // from this point on all possible 'throwers' are checked
+            flags &= ~FUNCFLAGnothrowInprocess;
+
+            if (isSynchronized())
+            {
+                /* Wrap the entire function body in a synchronized statement
+                 */
+                ClassDeclaration *cd = isThis() ? isThis()->isClassDeclaration() : parent->isClassDeclaration();
+
+                if (cd)
+                {
+                    if (!global.params.is64bit &&
+                        global.params.isWindows &&
+                        !isStatic() && !sbody->usesEH() && !global.params.trace)
+                    {
+                        /* The back end uses the "jmonitor" hack for syncing;
+                         * no need to do the sync at this level.
+                         */
+                    }
+                    else
+                    {
+                        Expression *vsync;
+                        if (isStatic())
+                        {
+                            // The monitor is in the ClassInfo
+                            vsync = new DotIdExp(loc, resolve(loc, sc2, cd, false), Id::classinfo);
+                        }
+                        else
+                        {
+                            // 'this' is the monitor
+                            vsync = new VarExp(loc, vthis);
+                        }
+                        sbody = new PeelStatement(sbody);       // don't redo semantic()
+                        sbody = new SynchronizedStatement(loc, vsync, sbody);
+                        sbody = ::semantic(sbody, sc2);
+                    }
+                }
+                else
+                {
+                    error("synchronized function %s must be a member of a class", toChars());
+                }
+            }
+
+            // If declaration has no body, don't set sbody to prevent incorrect codegen.
+            InterfaceDeclaration *id = parent->isInterfaceDeclaration();
+            if (fbody || id && (fdensure || fdrequire) && isVirtual())
+                fbody = sbody;
+        }
+
+        // Fix up forward-referenced gotos
+        if (gotos)
+        {
+            for (size_t i = 0; i < gotos->dim; ++i)
+            {
+                (*gotos)[i]->checkLabel();
+            }
+        }
+
+        if (naked && (fensure || frequire))
+            error("naked assembly functions with contracts are not supported");
+
+        sc2->callSuper = 0;
+        sc2->pop();
+    }
+
+    if (checkClosure())
+    {
+        // We should be setting errors here instead of relying on the global error count.
+        //errors = true;
+    }
+
+    /* If function survived being marked as impure, then it is pure
+     */
+    if (flags & FUNCFLAGpurityInprocess)
+    {
+        flags &= ~FUNCFLAGpurityInprocess;
+        if (type == f)
+            f = (TypeFunction *)f->copy();
+        f->purity = PUREfwdref;
+    }
+
+    if (flags & FUNCFLAGsafetyInprocess)
+    {
+        flags &= ~FUNCFLAGsafetyInprocess;
+        if (type == f)
+            f = (TypeFunction *)f->copy();
+        f->trust = TRUSTsafe;
+    }
+
+    if (flags & FUNCFLAGnogcInprocess)
+    {
+        flags &= ~FUNCFLAGnogcInprocess;
+        if (type == f)
+            f = (TypeFunction *)f->copy();
+        f->isnogc = true;
+    }
+
+    if (flags & FUNCFLAGreturnInprocess)
+    {
+        flags &= ~FUNCFLAGreturnInprocess;
+        if (storage_class & STCreturn)
+        {
+            if (type == f)
+                f = (TypeFunction *)f->copy();
+            f->isreturn = true;
+        }
+    }
+
+    flags &= ~FUNCFLAGinferScope;
+
+    // Infer STCscope
+    if (parameters)
+    {
+        size_t nfparams = Parameter::dim(f->parameters);
+        assert(nfparams == parameters->dim);
+        for (size_t u = 0; u < parameters->dim; u++)
+        {
+            VarDeclaration *v = (*parameters)[u];
+            if (v->storage_class & STCmaybescope)
+            {
+                //printf("Inferring scope for %s\n", v->toChars());
+                Parameter *p = Parameter::getNth(f->parameters, u);
+                v->storage_class &= ~STCmaybescope;
+                v->storage_class |= STCscope | STCscopeinferred;
+                p->storageClass |= STCscope | STCscopeinferred;
+                assert(!(p->storageClass & STCmaybescope));
+            }
+        }
+    }
+
+    if (vthis && vthis->storage_class & STCmaybescope)
+    {
+        vthis->storage_class &= ~STCmaybescope;
+        vthis->storage_class |= STCscope | STCscopeinferred;
+        f->isscope = true;
+        f->isscopeinferred = true;
+    }
+
+    // reset deco to apply inference result to mangled name
+    if (f != type)
+        f->deco = NULL;
+
+    // Do semantic type AFTER pure/nothrow inference.
+    if (!f->deco && ident != Id::xopEquals && ident != Id::xopCmp)
+    {
+        sc = sc->push();
+        if (isCtorDeclaration()) // Bugzilla #15665
+            sc->flags |= SCOPEctor;
+        sc->stc = 0;
+        sc->linkage = linkage;  // Bugzilla 8496
+        type = f->semantic(loc, sc);
+        sc = sc->pop();
+    }
+
+    /* If this function had instantiated with gagging, error reproduction will be
+     * done by TemplateInstance::semantic.
+     * Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
+     */
+    semanticRun = PASSsemantic3done;
+    semantic3Errors = (global.errors != oldErrors) || (fbody && fbody->isErrorStatement());
+    if (type->ty == Terror)
+        errors = true;
+    //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars());
+    //fflush(stdout);
+}
+
+/****************************************************
+ * Resolve forward reference of function signature -
+ * parameter types, return type, and attributes.
+ * Returns false if any errors exist in the signature.
+ */
+bool FuncDeclaration::functionSemantic()
+{
+    if (!_scope)
+        return !errors;
+
+    if (!originalType)      // semantic not yet run
+    {
+        TemplateInstance *spec = isSpeculative();
+        unsigned olderrs = global.errors;
+        unsigned oldgag = global.gag;
+        if (global.gag && !spec)
+            global.gag = 0;
+        semantic(_scope);
+        global.gag = oldgag;
+        if (spec && global.errors != olderrs)
+            spec->errors = (global.errors - olderrs != 0);
+        if (olderrs != global.errors)   // if errors compiling this function
+            return false;
+    }
+
+    // if inferring return type, sematic3 needs to be run
+    // - When the function body contains any errors, we cannot assume
+    //   the inferred return type is valid.
+    //   So, the body errors should become the function signature error.
+    if (inferRetType && type && !type->nextOf())
+        return functionSemantic3();
+
+    TemplateInstance *ti;
+    if (isInstantiated() && !isVirtualMethod() &&
+        !(ti = parent->isTemplateInstance(), ti && !ti->isTemplateMixin() && ti->tempdecl->ident != ident))
+    {
+        AggregateDeclaration *ad = isMember2();
+        if (ad && ad->sizeok != SIZEOKdone)
+        {
+            /* Currently dmd cannot resolve forward references per methods,
+             * then setting SIZOKfwd is too conservative and would break existing code.
+             * So, just stop method attributes inference until ad->semantic() done.
+             */
+            //ad->sizeok = SIZEOKfwd;
+        }
+        else
+            return functionSemantic3() || !errors;
+    }
+
+    if (storage_class & STCinference)
+        return functionSemantic3() || !errors;
+
+    return !errors;
+}
+
+/****************************************************
+ * Resolve forward reference of function body.
+ * Returns false if any errors exist in the body.
+ */
+bool FuncDeclaration::functionSemantic3()
+{
+    if (semanticRun < PASSsemantic3 && _scope)
+    {
+        /* Forward reference - we need to run semantic3 on this function.
+         * If errors are gagged, and it's not part of a template instance,
+         * we need to temporarily ungag errors.
+         */
+        TemplateInstance *spec = isSpeculative();
+        unsigned olderrs = global.errors;
+        unsigned oldgag = global.gag;
+        if (global.gag && !spec)
+            global.gag = 0;
+        semantic3(_scope);
+        global.gag = oldgag;
+
+        // If it is a speculatively-instantiated template, and errors occur,
+        // we need to mark the template as having errors.
+        if (spec && global.errors != olderrs)
+            spec->errors = (global.errors - olderrs != 0);
+        if (olderrs != global.errors)   // if errors compiling this function
+            return false;
+    }
+
+    return !errors && !semantic3Errors;
+}
+
+/****************************************************
+ * Check that this function type is properly resolved.
+ * If not, report "forward reference error" and return true.
+ */
+bool FuncDeclaration::checkForwardRef(Loc loc)
+{
+    if (!functionSemantic())
+        return true;
+
+    /* No deco means the functionSemantic() call could not resolve
+     * forward referenes in the type of this function.
+     */
+    if (!type->deco)
+    {
+        bool inSemantic3 = (inferRetType && semanticRun >= PASSsemantic3);
+        ::error(loc, "forward reference to %s'%s'",
+            (inSemantic3 ? "inferred return type of function " : ""),
+            toChars());
+        return true;
+    }
+    return false;
+}
+
+VarDeclaration *FuncDeclaration::declareThis(Scope *sc, AggregateDeclaration *ad)
+{
+    if (ad)
+    {
+        VarDeclaration *v;
+        {
+            //printf("declareThis() %s\n", toChars());
+            Type *thandle = ad->handleType();
+            assert(thandle);
+            thandle = thandle->addMod(type->mod);
+            thandle = thandle->addStorageClass(storage_class);
+            v = new ThisDeclaration(loc, thandle);
+            v->storage_class |= STCparameter;
+            if (thandle->ty == Tstruct)
+            {
+                v->storage_class |= STCref;
+
+                // if member function is marked 'inout', then 'this' is 'return ref'
+                if (type->ty == Tfunction && ((TypeFunction *)type)->iswild & 2)
+                    v->storage_class |= STCreturn;
+            }
+            if (type->ty == Tfunction)
+            {
+                TypeFunction *tf = (TypeFunction *)type;
+                if (tf->isreturn)
+                    v->storage_class |= STCreturn;
+                if (tf->isscope)
+                    v->storage_class |= STCscope;
+            }
+            if (flags & FUNCFLAGinferScope)
+                v->storage_class |= STCmaybescope;
+
+            v->semantic(sc);
+            if (!sc->insert(v))
+                assert(0);
+            v->parent = this;
+            return v;
+        }
+    }
+    else if (isNested())
+    {
+        /* The 'this' for a nested function is the link to the
+         * enclosing function's stack frame.
+         * Note that nested functions and member functions are disjoint.
+         */
+        VarDeclaration *v = new ThisDeclaration(loc, Type::tvoid->pointerTo());
+        v->storage_class |= STCparameter;
+        v->semantic(sc);
+        if (!sc->insert(v))
+            assert(0);
+        v->parent = this;
+        return v;
+    }
+
+    return NULL;
+}
+
+bool FuncDeclaration::equals(RootObject *o)
+{
+    if (this == o)
+        return true;
+
+    Dsymbol *s = isDsymbol(o);
+    if (s)
+    {
+        FuncDeclaration *fd1 = this;
+        FuncDeclaration *fd2 = s->isFuncDeclaration();
+        if (!fd2)
+            return false;
+
+        FuncAliasDeclaration *fa1 = fd1->isFuncAliasDeclaration();
+        FuncAliasDeclaration *fa2 = fd2->isFuncAliasDeclaration();
+        if (fa1 && fa2)
+        {
+            return fa1->toAliasFunc()->equals(fa2->toAliasFunc()) &&
+                   fa1->hasOverloads == fa2->hasOverloads;
+        }
+
+        if (fa1 && (fd1 = fa1->toAliasFunc())->isUnique() && !fa1->hasOverloads)
+            fa1 = NULL;
+        if (fa2 && (fd2 = fa2->toAliasFunc())->isUnique() && !fa2->hasOverloads)
+            fa2 = NULL;
+        if ((fa1 != NULL) != (fa2 != NULL))
+            return false;
+
+        return fd1->toParent()->equals(fd2->toParent()) &&
+            fd1->ident->equals(fd2->ident) && fd1->type->equals(fd2->type);
+    }
+    return false;
+}
+
+/****************************************************
+ * Declare result variable lazily.
+ */
+
+void FuncDeclaration::buildResultVar(Scope *sc, Type *tret)
+{
+    if (!vresult)
+    {
+        Loc loc = fensure ? fensure->loc : this->loc;
+
+        /* If inferRetType is true, tret may not be a correct return type yet.
+         * So, in here it may be a temporary type for vresult, and after
+         * fbody->semantic() running, vresult->type might be modified.
+         */
+        vresult = new VarDeclaration(loc, tret, outId ? outId : Id::result, NULL);
+        vresult->storage_class |= STCnodtor;
+
+        if (outId == Id::result)
+            vresult->storage_class |= STCtemp;
+        if (!isVirtual())
+            vresult->storage_class |= STCconst;
+        vresult->storage_class |= STCresult;
+
+        // set before the semantic() for checkNestedReference()
+        vresult->parent = this;
+    }
+
+    if (sc && vresult->semanticRun == PASSinit)
+    {
+        assert(type->ty == Tfunction);
+        TypeFunction *tf = (TypeFunction *)type;
+        if (tf->isref)
+            vresult->storage_class |= STCref;
+        vresult->type = tret;
+
+        vresult->semantic(sc);
+
+        if (!sc->insert(vresult))
+            error("out result %s is already defined", vresult->toChars());
+        assert(vresult->parent == this);
+    }
+}
+
+/****************************************************
+ * Merge into this function the 'in' contracts of all it overrides.
+ * 'in's are OR'd together, i.e. only one of them needs to pass.
+ */
+
+Statement *FuncDeclaration::mergeFrequire(Statement *sf)
+{
+    /* If a base function and its override both have an IN contract, then
+     * only one of them needs to succeed. This is done by generating:
+     *
+     * void derived.in() {
+     *  try {
+     *    base.in();
+     *  }
+     *  catch () {
+     *    ... body of derived.in() ...
+     *  }
+     * }
+     *
+     * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
+     * If base.in() throws, then derived.in()'s body is executed.
+     */
+
+    /* Implementing this is done by having the overriding function call
+     * nested functions (the fdrequire functions) nested inside the overridden
+     * function. This requires that the stack layout of the calling function's
+     * parameters and 'this' pointer be in the same place (as the nested
+     * function refers to them).
+     * This is easy for the parameters, as they are all on the stack in the same
+     * place by definition, since it's an overriding function. The problem is
+     * getting the 'this' pointer in the same place, since it is a local variable.
+     * We did some hacks in the code generator to make this happen:
+     *  1. always generate exception handler frame, or at least leave space for it
+     *     in the frame (Windows 32 SEH only)
+     *  2. always generate an EBP style frame
+     *  3. since 'this' is passed in a register that is subsequently copied into
+     *     a stack local, allocate that local immediately following the exception
+     *     handler block, so it is always at the same offset from EBP.
+     */
+    for (size_t i = 0; i < foverrides.dim; i++)
+    {
+        FuncDeclaration *fdv = foverrides[i];
+
+        /* The semantic pass on the contracts of the overridden functions must
+         * be completed before code generation occurs.
+         * https://issues.dlang.org/show_bug.cgi?id=3602
+         */
+        if (fdv->frequire && fdv->semanticRun != PASSsemantic3done)
+        {
+            assert(fdv->_scope);
+            Scope *sc = fdv->_scope->push();
+            sc->stc &= ~STCoverride;
+            fdv->semantic3(sc);
+            sc->pop();
+        }
+
+        sf = fdv->mergeFrequire(sf);
+        if (sf && fdv->fdrequire)
+        {
+            //printf("fdv->frequire: %s\n", fdv->frequire->toChars());
+            /* Make the call:
+             *   try { __require(); }
+             *   catch { frequire; }
+             */
+            Expression *eresult = NULL;
+            Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire, false), eresult);
+            Statement *s2 = new ExpStatement(loc, e);
+
+            Catch *c = new Catch(loc, NULL, NULL, sf);
+            c->internalCatch = true;
+            Catches *catches = new Catches();
+            catches->push(c);
+            sf = new TryCatchStatement(loc, s2, catches);
+        }
+        else
+            return NULL;
+    }
+    return sf;
+}
+
+/****************************************************
+ * Merge into this function the 'out' contracts of all it overrides.
+ * 'out's are AND'd together, i.e. all of them need to pass.
+ */
+
+Statement *FuncDeclaration::mergeFensure(Statement *sf, Identifier *oid)
+{
+    /* Same comments as for mergeFrequire(), except that we take care
+     * of generating a consistent reference to the 'result' local by
+     * explicitly passing 'result' to the nested function as a reference
+     * argument.
+     * This won't work for the 'this' parameter as it would require changing
+     * the semantic code for the nested function so that it looks on the parameter
+     * list for the 'this' pointer, something that would need an unknown amount
+     * of tweaking of various parts of the compiler that I'd rather leave alone.
+     */
+    for (size_t i = 0; i < foverrides.dim; i++)
+    {
+        FuncDeclaration *fdv = foverrides[i];
+
+        /* The semantic pass on the contracts of the overridden functions must
+         * be completed before code generation occurs.
+         * https://issues.dlang.org/show_bug.cgi?id=3602 and
+         * https://issues.dlang.org/show_bug.cgi?id=5230
+         */
+        if (needsFensure(fdv) && fdv->semanticRun != PASSsemantic3done)
+        {
+            assert(fdv->_scope);
+            Scope *sc = fdv->_scope->push();
+            sc->stc &= ~STCoverride;
+            fdv->semantic3(sc);
+            sc->pop();
+        }
+
+        sf = fdv->mergeFensure(sf, oid);
+        if (fdv->fdensure)
+        {
+            //printf("fdv->fensure: %s\n", fdv->fensure->toChars());
+            // Make the call: __ensure(result)
+            Expression *eresult = NULL;
+            if (outId)
+            {
+                eresult = new IdentifierExp(loc, oid);
+
+                Type *t1 = fdv->type->nextOf()->toBasetype();
+                Type *t2 = this->type->nextOf()->toBasetype();
+                if (t1->isBaseOf(t2, NULL))
+                {
+                    /* Making temporary reference variable is necessary
+                     * in covariant return.
+                     * See bugzilla 5204 and 10479.
+                     */
+                    ExpInitializer *ei = new ExpInitializer(Loc(), eresult);
+                    VarDeclaration *v = new VarDeclaration(Loc(), t1, Identifier::generateId("__covres"), ei);
+                    v->storage_class |= STCtemp;
+                    DeclarationExp *de = new DeclarationExp(Loc(), v);
+                    VarExp *ve = new VarExp(Loc(), v);
+                    eresult = new CommaExp(Loc(), de, ve);
+                }
+            }
+            Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure, false), eresult);
+            Statement *s2 = new ExpStatement(loc, e);
+
+            if (sf)
+            {
+                sf = new CompoundStatement(sf->loc, s2, sf);
+            }
+            else
+                sf = s2;
+        }
+    }
+    return sf;
+}
+
+/****************************************************
+ * Determine if 'this' overrides fd.
+ * Return !=0 if it does.
+ */
+
+int FuncDeclaration::overrides(FuncDeclaration *fd)
+{   int result = 0;
+
+    if (fd->ident == ident)
+    {
+        int cov = type->covariant(fd->type);
+        if (cov)
+        {   ClassDeclaration *cd1 = toParent()->isClassDeclaration();
+            ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration();
+
+            if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL))
+                result = 1;
+        }
+    }
+    return result;
+}
+
+/*************************************************
+ * Find index of function in vtbl[0..dim] that
+ * this function overrides.
+ * Prefer an exact match to a covariant one.
+ * Params:
+ *      fix17349 = enable fix https://issues.dlang.org/show_bug.cgi?id=17349
+ * Returns:
+ *      -1      didn't find one
+ *      -2      can't determine because of forward references
+ */
+
+int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim, bool fix17349)
+{
+    //printf("findVtblIndex() %s\n", toChars());
+    FuncDeclaration *mismatch = NULL;
+    StorageClass mismatchstc = 0;
+    int mismatchvi = -1;
+    int exactvi = -1;
+    int bestvi = -1;
+    for (int vi = 0; vi < dim; vi++)
+    {
+        FuncDeclaration *fdv = (*vtbl)[vi]->isFuncDeclaration();
+        if (fdv && fdv->ident == ident)
+        {
+            if (type->equals(fdv->type))        // if exact match
+            {
+                if (fdv->parent->isClassDeclaration())
+                    return vi;                  // no need to look further
+
+                if (exactvi >= 0)
+                {
+                    error("cannot determine overridden function");
+                    return exactvi;
+                }
+                exactvi = vi;
+
+                bestvi = vi;
+                continue;
+            }
+
+            StorageClass stc = 0;
+            int cov = type->covariant(fdv->type, &stc, fix17349);
+            //printf("\tbaseclass cov = %d\n", cov);
+            switch (cov)
+            {
+                case 0:         // types are distinct
+                    break;
+
+                case 1:
+                    bestvi = vi;        // covariant, but not identical
+                    break;              // keep looking for an exact match
+
+                case 2:
+                    mismatchvi = vi;
+                    mismatchstc = stc;
+                    mismatch = fdv;     // overrides, but is not covariant
+                    break;              // keep looking for an exact match
+
+                case 3:
+                    return -2;  // forward references
+
+                default:
+                    assert(0);
+            }
+        }
+    }
+    if (bestvi == -1 && mismatch)
+    {
+        //type->print();
+        //mismatch->type->print();
+        //printf("%s %s\n", type->deco, mismatch->type->deco);
+        //printf("stc = %llx\n", mismatchstc);
+        if (mismatchstc)
+        {   // Fix it by modifying the type to add the storage classes
+            type = type->addStorageClass(mismatchstc);
+            bestvi = mismatchvi;
+        }
+    }
+    return bestvi;
+}
+
+/*********************************
+ * If function a function in a base class,
+ * return that base class.
+ * Params:
+ *  cd = class that function is in
+ * Returns:
+ *  base class if overriding, NULL if not
+ */
+BaseClass *FuncDeclaration::overrideInterface()
+{
+    ClassDeclaration *cd = parent->isClassDeclaration();
+    for (size_t i = 0; i < cd->interfaces.length; i++)
+    {
+        BaseClass *b = cd->interfaces.ptr[i];
+        int v = findVtblIndex((Dsymbols *)&b->sym->vtbl, (int)b->sym->vtbl.dim);
+        if (v >= 0)
+            return b;
+    }
+    return NULL;
+}
+
+/****************************************************
+ * Overload this FuncDeclaration with the new one f.
+ * Return true if successful; i.e. no conflict.
+ */
+
+bool FuncDeclaration::overloadInsert(Dsymbol *s)
+{
+    //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s->toChars(), toChars());
+    assert(s != this);
+
+    AliasDeclaration *ad = s->isAliasDeclaration();
+    if (ad)
+    {
+        if (overnext)
+            return overnext->overloadInsert(ad);
+        if (!ad->aliassym && ad->type->ty != Tident && ad->type->ty != Tinstance)
+        {
+            //printf("\tad = '%s'\n", ad->type->toChars());
+            return false;
+        }
+        overnext = ad;
+        //printf("\ttrue: no conflict\n");
+        return true;
+    }
+    TemplateDeclaration *td = s->isTemplateDeclaration();
+    if (td)
+    {
+        if (!td->funcroot)
+            td->funcroot = this;
+        if (overnext)
+            return overnext->overloadInsert(td);
+        overnext = td;
+        return true;
+    }
+    FuncDeclaration *fd = s->isFuncDeclaration();
+    if (!fd)
+        return false;
+
+#if 0
+    /* Disable this check because:
+     *  const void foo();
+     * semantic() isn't run yet on foo(), so the const hasn't been
+     * applied yet.
+     */
+    if (type)
+    {   printf("type = %s\n", type->toChars());
+        printf("fd->type = %s\n", fd->type->toChars());
+    }
+    // fd->type can be NULL for overloaded constructors
+    if (type && fd->type &&
+        fd->type->covariant(type) &&
+        fd->type->mod == type->mod &&
+        !isFuncAliasDeclaration())
+    {
+        //printf("\tfalse: conflict %s\n", kind());
+        return false;
+    }
+#endif
+
+    if (overnext)
+    {
+        td = overnext->isTemplateDeclaration();
+        if (td)
+            fd->overloadInsert(td);
+        else
+            return overnext->overloadInsert(fd);
+    }
+    overnext = fd;
+    //printf("\ttrue: no conflict\n");
+    return true;
+}
+
+/***************************************************
+ * Visit each overloaded function/template in turn, and call
+ * (*fp)(param, s) on it.
+ * Exit when no more, or (*fp)(param, f) returns nonzero.
+ * Returns:
+ *      ==0     continue
+ *      !=0     done
+ */
+
+int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *))
+{
+    Dsymbol *d;
+    Dsymbol *next;
+    for (d = fstart; d; d = next)
+    {
+        if (OverDeclaration *od = d->isOverDeclaration())
+        {
+            if (od->hasOverloads)
+            {
+                if (int r = overloadApply(od->aliassym, param, fp))
+                    return r;
+            }
+            else
+            {
+                if (int r = (*fp)(param, od->aliassym))
+                    return r;
+            }
+            next = od->overnext;
+        }
+        else if (FuncAliasDeclaration *fa = d->isFuncAliasDeclaration())
+        {
+            if (fa->hasOverloads)
+            {
+                if (int r = overloadApply(fa->funcalias, param, fp))
+                    return r;
+            }
+            else
+            {
+                FuncDeclaration *fd = fa->toAliasFunc();
+                if (!fd)
+                {
+                    d->error("is aliased to a function");
+                    break;
+                }
+                if (int r = (*fp)(param, fd))
+                    return r;
+            }
+            next = fa->overnext;
+        }
+        else if (AliasDeclaration *ad = d->isAliasDeclaration())
+        {
+            next = ad->toAlias();
+            if (next == ad)
+                break;
+            if (next == fstart)
+                break;
+        }
+        else if (TemplateDeclaration *td = d->isTemplateDeclaration())
+        {
+            if (int r = (*fp)(param, td))
+                return r;
+            next = td->overnext;
+        }
+        else
+        {
+            FuncDeclaration *fd = d->isFuncDeclaration();
+            if (!fd)
+            {
+                d->error("is aliased to a function");
+                break;              // BUG: should print error message?
+            }
+            if (int r = (*fp)(param, fd))
+                return r;
+            next = fd->overnext;
+        }
+    }
+    return 0;
+}
+
+/********************************************
+ * If there are no overloads of function f, return that function,
+ * otherwise return NULL.
+ */
+
+FuncDeclaration *FuncDeclaration::isUnique()
+{
+  struct ParamUnique
+  {
+    static int fp(void *param, Dsymbol *s)
+    {
+        FuncDeclaration *f = s->isFuncDeclaration();
+        if (!f)
+            return 0;
+        FuncDeclaration **pf = (FuncDeclaration **)param;
+
+        if (*pf)
+        {
+            *pf = NULL;
+            return 1;               // ambiguous, done
+        }
+        else
+        {
+            *pf = f;
+            return 0;
+        }
+    }
+  };
+    FuncDeclaration *result = NULL;
+    overloadApply(this, &result, &ParamUnique::fp);
+    return result;
+}
+
+/********************************************
+ * Find function in overload list that exactly matches t.
+ */
+
+FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t)
+{
+  struct ParamExact
+  {
+    Type *t;            // type to match
+    FuncDeclaration *f; // return value
+
+    static int fp(void *param, Dsymbol *s)
+    {
+        FuncDeclaration *f = s->isFuncDeclaration();
+        if (!f)
+            return 0;
+        ParamExact *p = (ParamExact *)param;
+        Type *t = p->t;
+
+        if (t->equals(f->type))
+        {
+            p->f = f;
+            return 1;
+        }
+
+        /* Allow covariant matches, as long as the return type
+         * is just a const conversion.
+         * This allows things like pure functions to match with an impure function type.
+         */
+        if (t->ty == Tfunction)
+        {   TypeFunction *tf = (TypeFunction *)f->type;
+            if (tf->covariant(t) == 1 &&
+                tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst)
+            {
+                p->f = f;
+                return 1;
+            }
+        }
+        return 0;
+    }
+  };
+    ParamExact p;
+    p.t = t;
+    p.f = NULL;
+    overloadApply(this, &p, &ParamExact::fp);
+    return p.f;
+}
+
+static void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod)
+{
+    bool bothMutable = ((lhsMod & rhsMod) == 0);
+    bool sharedMismatch = ((lhsMod ^ rhsMod) & MODshared) != 0;
+    bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODshared);
+
+    if (lhsMod & MODshared)
+        buf->writestring("shared ");
+    else if (sharedMismatch && !(lhsMod & MODimmutable))
+        buf->writestring("non-shared ");
+
+    if (bothMutable && sharedMismatchOnly)
+    { }
+    else if (lhsMod & MODimmutable)
+        buf->writestring("immutable ");
+    else if (lhsMod & MODconst)
+        buf->writestring("const ");
+    else if (lhsMod & MODwild)
+        buf->writestring("inout ");
+    else
+        buf->writestring("mutable ");
+}
+
+/********************************************
+ * Find function in overload list that matches to the 'this' modifier.
+ * There's four result types.
+ *
+ * 1. If the 'tthis' matches only one candidate, it's an "exact match".
+ *    Returns the function and 'hasOverloads' is set to false.
+ *      eg. If 'tthis" is mutable and there's only one mutable method.
+ * 2. If there's two or more match candidates, but a candidate function will be
+ *    a "better match".
+ *    Returns the better match function but 'hasOverloads' is set to true.
+ *      eg. If 'tthis' is mutable, and there's both mutable and const methods,
+ *          the mutable method will be a better match.
+ * 3. If there's two or more match candidates, but there's no better match,
+ *    Returns NULL and 'hasOverloads' is set to true to represent "ambiguous match".
+ *      eg. If 'tthis' is mutable, and there's two or more mutable methods.
+ * 4. If there's no candidates, it's "no match" and returns NULL with error report.
+ *      e.g. If 'tthis' is const but there's no const methods.
+ */
+FuncDeclaration *FuncDeclaration::overloadModMatch(Loc loc, Type *tthis, bool &hasOverloads)
+{
+    //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
+    Match m;
+    memset(&m, 0, sizeof(m));
+    m.last = MATCHnomatch;
+
+  struct ParamMod
+  {
+    Match *m;
+    Type *tthis;
+
+    static int fp(void *param, Dsymbol *s)
+    {
+        if (FuncDeclaration *fd = s->isFuncDeclaration())
+            return ((ParamMod *)param)->fp(fd);
+        return 0;
+    }
+    int fp(FuncDeclaration *f)
+    {
+        if (f == m->lastf)          // skip duplicates
+            return 0;
+
+        m->anyf = f;
+        TypeFunction *tf = (TypeFunction *)f->type;
+        //printf("tf = %s\n", tf->toChars());
+
+        MATCH match;
+        if (tthis)   // non-static functions are preferred than static ones
+        {
+            if (f->needThis())
+                match = f->isCtorDeclaration() ? MATCHexact : MODmethodConv(tthis->mod, tf->mod);
+            else
+                match = MATCHconst; // keep static funciton in overload candidates
+        }
+        else            // static functions are preferred than non-static ones
+        {
+            if (f->needThis())
+                match = MATCHconvert;
+            else
+                match = MATCHexact;
+        }
+        if (match != MATCHnomatch)
+        {
+            if (match > m->last) goto LfIsBetter;
+            if (match < m->last) goto LlastIsBetter;
+
+            /* See if one of the matches overrides the other.
+             */
+            if (m->lastf->overrides(f)) goto LlastIsBetter;
+            if (f->overrides(m->lastf)) goto LfIsBetter;
+
+        Lambiguous:
+            //printf("\tambiguous\n");
+            m->nextf = f;
+            m->count++;
+            return 0;
+
+        LlastIsBetter:
+            //printf("\tlastbetter\n");
+            m->count++; // count up
+            return 0;
+
+        LfIsBetter:
+            //printf("\tisbetter\n");
+            if (m->last <= MATCHconvert)
+            {
+                // clear last secondary matching
+                m->nextf = NULL;
+                m->count = 0;
+            }
+            m->last = match;
+            m->lastf = f;
+            m->count++;     // count up
+            return 0;
+        }
+        return 0;
+    }
+  };
+    ParamMod p;
+    p.m = &m;
+    p.tthis = tthis;
+    overloadApply(this, &p, &ParamMod::fp);
+
+    if (m.count == 1)       // exact match
+    {
+        hasOverloads = false;
+    }
+    else if (m.count > 1)   // better or ambiguous match
+    {
+        hasOverloads = true;
+    }
+    else                    // no match
+    {
+        hasOverloads = true;
+        TypeFunction *tf = (TypeFunction *)this->type;
+        assert(tthis);
+        assert(!MODimplicitConv(tthis->mod, tf->mod));  // modifier mismatch
+        {
+            OutBuffer thisBuf, funcBuf;
+            MODMatchToBuffer(&thisBuf, tthis->mod, tf->mod);
+            MODMatchToBuffer(&funcBuf, tf->mod, tthis->mod);
+            ::error(loc, "%smethod %s is not callable using a %sobject",
+                funcBuf.peekString(), this->toPrettyChars(), thisBuf.peekString());
+        }
+    }
+
+    return m.lastf;
+}
+
+/********************************************
+ * Returns true if function was declared
+ * directly or indirectly in a unittest block
+ */
+bool FuncDeclaration::inUnittest()
+{
+    Dsymbol *f = this;
+    do
+    {
+        if (f->isUnitTestDeclaration())
+            return true;
+        f = f->toParent();
+    } while (f);
+
+    return false;
+}
+
+/********************************************
+ * find function template root in overload list
+ */
+
+TemplateDeclaration *FuncDeclaration::findTemplateDeclRoot()
+{
+    FuncDeclaration *f = this;
+    while (f && f->overnext)
+    {
+        //printf("f->overnext = %p %s\n", f->overnext, f->overnext->toChars());
+        TemplateDeclaration *td = f->overnext->isTemplateDeclaration();
+        if (td)
+            return td;
+        f = f->overnext->isFuncDeclaration();
+    }
+    return NULL;
+}
+
+/*************************************
+ * Determine partial specialization order of 'this' vs g.
+ * This is very similar to TemplateDeclaration::leastAsSpecialized().
+ * Returns:
+ *      match   'this' is at least as specialized as g
+ *      0       g is more specialized than 'this'
+ */
+
+MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g)
+{
+#define LOG_LEASTAS     0
+
+#if LOG_LEASTAS
+    printf("%s.leastAsSpecialized(%s)\n", toChars(), g->toChars());
+    printf("%s, %s\n", type->toChars(), g->type->toChars());
+#endif
+
+    /* This works by calling g() with f()'s parameters, and
+     * if that is possible, then f() is at least as specialized
+     * as g() is.
+     */
+
+    TypeFunction *tf = (TypeFunction *)type;
+    TypeFunction *tg = (TypeFunction *)g->type;
+    size_t nfparams = Parameter::dim(tf->parameters);
+
+    /* If both functions have a 'this' pointer, and the mods are not
+     * the same and g's is not const, then this is less specialized.
+     */
+    if (needThis() && g->needThis() && tf->mod != tg->mod)
+    {
+        if (isCtorDeclaration())
+        {
+            if (!MODimplicitConv(tg->mod, tf->mod))
+                return MATCHnomatch;
+        }
+        else
+        {
+            if (!MODimplicitConv(tf->mod, tg->mod))
+                return MATCHnomatch;
+        }
+    }
+
+    /* Create a dummy array of arguments out of the parameters to f()
+     */
+    Expressions args;
+    args.setDim(nfparams);
+    for (size_t u = 0; u < nfparams; u++)
+    {
+        Parameter *p = Parameter::getNth(tf->parameters, u);
+        Expression *e;
+        if (p->storageClass & (STCref | STCout))
+        {
+            e = new IdentifierExp(Loc(), p->ident);
+            e->type = p->type;
+        }
+        else
+            e = p->type->defaultInitLiteral(Loc());
+        args[u] = e;
+    }
+
+    MATCH m = (MATCH) tg->callMatch(NULL, &args, 1);
+    if (m > MATCHnomatch)
+    {
+        /* A variadic parameter list is less specialized than a
+         * non-variadic one.
+         */
+        if (tf->varargs && !tg->varargs)
+            goto L1;    // less specialized
+
+#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;
+}
+
+/// Walk through candidate template overloads and print them in the diagnostics.
+struct TemplateCandidateWalker
+{
+    Loc loc;
+    int numToDisplay;  // max num of overloads to print (-v overrides this).
+
+    /// Count template overloads.
+    struct CountWalker
+    {
+        int numOverloads;
+
+        static int fp(void *param, Dsymbol *s)
+        {
+            CountWalker *p = (CountWalker *)param;
+            ++(p->numOverloads);
+            return 0;
+        }
+    };
+
+    static int fp(void *param, Dsymbol *s)
+    {
+        TemplateDeclaration *t = s->isTemplateDeclaration();
+        if (!t) return 0;
+
+        TemplateCandidateWalker *p = (TemplateCandidateWalker *)param;
+
+        ::errorSupplemental(t->loc, "%s", t->toPrettyChars());
+
+        if (!global.params.verbose && --(p->numToDisplay) == 0 && t->overnext)
+        {
+            // Too many overloads to sensibly display.
+            // Just show count of remaining overloads.
+            CountWalker cw;
+            cw.numOverloads = 0;
+            overloadApply(t->overnext, &cw, &CountWalker::fp);
+
+            if (cw.numOverloads > 0)
+                ::errorSupplemental(p->loc, "... (%d more, -v to show) ...", cw.numOverloads);
+
+            return 1;  // stop iterating
+        }
+
+        return 0;
+    }
+};
+
+/// Walk through candidate template overloads and print them in the diagnostics.
+struct FuncCandidateWalker
+{
+    Loc loc;
+    int numToDisplay;  // max num of overloads to print (-v overrides this).
+
+    /// Count function overloads.
+    struct CountWalker
+    {
+        int numOverloads;
+
+        static int fp(void *param, Dsymbol *s)
+        {
+            CountWalker *p = (CountWalker *)param;
+
+            if (s->isFuncDeclaration())
+                ++(p->numOverloads);
+
+            return 0;
+        }
+    };
+
+    static int fp(void *param, Dsymbol *s)
+    {
+        FuncDeclaration *f = s->isFuncDeclaration();
+        if (!f || f->errors || f->type->ty == Terror)
+            return 0;
+
+        FuncCandidateWalker *p = (FuncCandidateWalker *)param;
+        TypeFunction *tf = (TypeFunction *)f->type;
+
+        ::errorSupplemental(f->loc, "%s%s", f->toPrettyChars(),
+            parametersTypeToChars(tf->parameters, tf->varargs));
+
+        if (!global.params.verbose && --(p->numToDisplay) == 0 && f->overnext)
+        {
+            CountWalker cw;
+            cw.numOverloads = 0;
+            overloadApply(f->overnext, &cw, &CountWalker::fp);
+
+            if (cw.numOverloads > 0)
+                ::errorSupplemental(p->loc, "... (%d more, -v to show) ...", cw.numOverloads);
+
+            return 1;  // stop iterating
+        }
+
+        return 0;
+    }
+};
+
+/*******************************************
+ * Given a symbol that could be either a FuncDeclaration or
+ * a function template, resolve it to a function symbol.
+ *      loc             instantiation location
+ *      sc              instantiation scope
+ *      tiargs          initial list of template arguments
+ *      tthis           if !NULL, the 'this' pointer argument
+ *      fargs           arguments to function
+ *      flags           1: do not issue error message on no match, just return NULL
+ *                      2: overloadResolve only
+ */
+
+FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
+        Objects *tiargs, Type *tthis, Expressions *fargs, int flags)
+{
+    if (!s)
+        return NULL;                    // no match
+
+#if 0
+    printf("resolveFuncCall('%s')\n", s->toChars());
+    if (fargs)
+    {
+        for (size_t i = 0; i < fargs->dim; i++)
+        {
+            Expression *arg = (*fargs)[i];
+            assert(arg->type);
+            printf("\t%s: ", arg->toChars());
+            arg->type->print();
+        }
+    }
+#endif
+
+    if (tiargs && arrayObjectIsError(tiargs) ||
+        fargs  && arrayObjectIsError((Objects *)fargs))
+    {
+        return NULL;
+    }
+
+    Match m;
+    memset(&m, 0, sizeof(m));
+    m.last = MATCHnomatch;
+
+    functionResolve(&m, s, loc, sc, tiargs, tthis, fargs);
+
+    if (m.last > MATCHnomatch && m.lastf)
+    {
+        if (m.count == 1)   // exactly one match
+        {
+            if (!(flags & 1))
+                m.lastf->functionSemantic();
+            return m.lastf;
+        }
+        if ((flags & 2) && !tthis && m.lastf->needThis())
+        {
+            return m.lastf;
+        }
+    }
+
+    /* Failed to find a best match.
+     * Do nothing or print error.
+     */
+    if (m.last <= MATCHnomatch)
+    {
+        // error was caused on matched function
+        if (m.count == 1)
+            return m.lastf;
+
+        // if do not print error messages
+        if (flags & 1)
+            return NULL;    // no match
+    }
+
+    FuncDeclaration *fd = s->isFuncDeclaration();
+    OverDeclaration *od = s->isOverDeclaration();
+    TemplateDeclaration *td = s->isTemplateDeclaration();
+    if (td && td->funcroot)
+        s = fd = td->funcroot;
+
+    OutBuffer tiargsBuf;
+    arrayObjectsToBuffer(&tiargsBuf, tiargs);
+
+    OutBuffer fargsBuf;
+    fargsBuf.writeByte('(');
+    argExpTypesToCBuffer(&fargsBuf, fargs);
+    fargsBuf.writeByte(')');
+    if (tthis)
+        tthis->modToBuffer(&fargsBuf);
+
+    const int numOverloadsDisplay = 5; // sensible number to display
+
+    if (!m.lastf && !(flags & 1))   // no match
+    {
+        if (td && !fd)  // all of overloads are templates
+        {
+            ::error(loc, "%s %s.%s cannot deduce function from argument types !(%s)%s, candidates are:",
+                    td->kind(), td->parent->toPrettyChars(), td->ident->toChars(),
+                    tiargsBuf.peekString(), fargsBuf.peekString());
+
+            // Display candidate templates (even if there are no multiple overloads)
+            TemplateCandidateWalker tcw;
+            tcw.loc = loc;
+            tcw.numToDisplay = numOverloadsDisplay;
+            overloadApply(td, &tcw, &TemplateCandidateWalker::fp);
+        }
+        else if (od)
+        {
+            ::error(loc, "none of the overloads of '%s' are callable using argument types !(%s)%s",
+                od->ident->toChars(), tiargsBuf.peekString(), fargsBuf.peekString());
+        }
+        else
+        {
+            assert(fd);
+
+            bool hasOverloads = fd->overnext != NULL;
+            TypeFunction *tf = (TypeFunction *)fd->type;
+            if (tthis && !MODimplicitConv(tthis->mod, tf->mod)) // modifier mismatch
+            {
+                OutBuffer thisBuf, funcBuf;
+                MODMatchToBuffer(&thisBuf, tthis->mod, tf->mod);
+                MODMatchToBuffer(&funcBuf, tf->mod, tthis->mod);
+                if (hasOverloads)
+                    ::error(loc, "none of the overloads of '%s' are callable using a %sobject, candidates are:",
+                        fd->ident->toChars(), thisBuf.peekString());
+                else
+                    ::error(loc, "%smethod %s is not callable using a %sobject",
+                        funcBuf.peekString(), fd->toPrettyChars(), thisBuf.peekString());
+            }
+            else
+            {
+                //printf("tf = %s, args = %s\n", tf->deco, (*fargs)[0]->type->deco);
+                if (hasOverloads)
+                    ::error(loc, "none of the overloads of '%s' are callable using argument types %s, candidates are:",
+                            fd->ident->toChars(), fargsBuf.peekString());
+                else
+                    fd->error(loc, "%s%s is not callable using argument types %s",
+                        parametersTypeToChars(tf->parameters, tf->varargs),
+                        tf->modToChars(),
+                        fargsBuf.peekString());
+            }
+
+            // Display candidate functions
+            if (hasOverloads)
+            {
+                FuncCandidateWalker fcw;
+                fcw.loc = loc;
+                fcw.numToDisplay = numOverloadsDisplay;
+                overloadApply(fd, &fcw, &FuncCandidateWalker::fp);
+            }
+        }
+    }
+    else if (m.nextf)
+    {
+        TypeFunction *tf1 = (TypeFunction *)m.lastf->type;
+        TypeFunction *tf2 = (TypeFunction *)m.nextf->type;
+        const char *lastprms = parametersTypeToChars(tf1->parameters, tf1->varargs);
+        const char *nextprms = parametersTypeToChars(tf2->parameters, tf2->varargs);
+        ::error(loc, "%s.%s called with argument types %s matches both:\n"
+                     "%s:     %s%s\nand:\n%s:     %s%s",
+                s->parent->toPrettyChars(), s->ident->toChars(),
+                fargsBuf.peekString(),
+                m.lastf->loc.toChars(), m.lastf->toPrettyChars(), lastprms,
+                m.nextf->loc.toChars(), m.nextf->toPrettyChars(), nextprms);
+    }
+    return NULL;
+}
+
+/********************************
+ * Labels are in a separate scope, one per function.
+ */
+
+LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident)
+{   Dsymbol *s;
+
+    if (!labtab)
+        labtab = new DsymbolTable();    // guess we need one
+
+    s = labtab->lookup(ident);
+    if (!s)
+    {
+        s = new LabelDsymbol(ident);
+        labtab->insert(s);
+    }
+    return (LabelDsymbol *)s;
+}
+
+/*****************************************
+ * Determine lexical level difference from 'this' to nested function 'fd'.
+ * Error if this cannot call fd.
+ * Returns:
+ *      0       same level
+ *      >0      decrease nesting by number
+ *      -1      increase nesting by 1 (fd is nested within 'this')
+ *      -2      error
+ */
+
+int FuncDeclaration::getLevel(Loc loc, Scope *sc, FuncDeclaration *fd)
+{
+    int level;
+    Dsymbol *s;
+    Dsymbol *fdparent;
+
+    //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars());
+    fdparent = fd->toParent2();
+    if (fdparent == this)
+        return -1;
+    s = this;
+    level = 0;
+    while (fd != s && fdparent != s->toParent2())
+    {
+        //printf("\ts = %s, '%s'\n", s->kind(), s->toChars());
+        FuncDeclaration *thisfd = s->isFuncDeclaration();
+        if (thisfd)
+        {
+            if (!thisfd->isNested() && !thisfd->vthis && !sc->intypeof)
+                goto Lerr;
+        }
+        else
+        {
+            AggregateDeclaration *thiscd = s->isAggregateDeclaration();
+            if (thiscd)
+            {
+                /* AggregateDeclaration::isNested returns true only when
+                 * it has a hidden pointer.
+                 * But, calling the function belongs unrelated lexical scope
+                 * is still allowed inside typeof.
+                 *
+                 * struct Map(alias fun) {
+                 *   typeof({ return fun(); }) RetType;
+                 *   // No member function makes Map struct 'not nested'.
+                 * }
+                 */
+                if (!thiscd->isNested() && !sc->intypeof)
+                    goto Lerr;
+            }
+            else
+                goto Lerr;
+        }
+
+        s = s->toParent2();
+        assert(s);
+        level++;
+    }
+    return level;
+
+Lerr:
+    // Don't give error if in template constraint
+    if (!(sc->flags & SCOPEconstraint))
+    {
+        const char *xstatic = isStatic() ? "static " : "";
+        // better diagnostics for static functions
+        ::error(loc, "%s%s %s cannot access frame of function %s",
+            xstatic, kind(), toPrettyChars(), fd->toPrettyChars());
+        return -2;
+    }
+    return 1;
+}
+
+const char *FuncDeclaration::toPrettyChars(bool QualifyTypes)
+{
+    if (isMain())
+        return "D main";
+    else
+        return Dsymbol::toPrettyChars(QualifyTypes);
+}
+
+/** for diagnostics, e.g. 'int foo(int x, int y) pure' */
+const char *FuncDeclaration::toFullSignature()
+{
+    OutBuffer buf;
+    functionToBufferWithIdent((TypeFunction *)type, &buf, toChars());
+    return buf.extractString();
+}
+
+bool FuncDeclaration::isMain()
+{
+    return ident == Id::main &&
+        linkage != LINKc && !isMember() && !isNested();
+}
+
+bool FuncDeclaration::isCMain()
+{
+    return ident == Id::main &&
+        linkage == LINKc && !isMember() && !isNested();
+}
+
+bool FuncDeclaration::isWinMain()
+{
+    //printf("FuncDeclaration::isWinMain() %s\n", toChars());
+#if 0
+    bool x = ident == Id::WinMain &&
+        linkage != LINKc && !isMember();
+    printf("%s\n", x ? "yes" : "no");
+    return x;
+#else
+    return ident == Id::WinMain &&
+        linkage != LINKc && !isMember();
+#endif
+}
+
+bool FuncDeclaration::isDllMain()
+{
+    return ident == Id::DllMain &&
+        linkage != LINKc && !isMember();
+}
+
+bool FuncDeclaration::isExport()
+{
+    return protection.kind == PROTexport;
+}
+
+bool FuncDeclaration::isImportedSymbol()
+{
+    //printf("isImportedSymbol()\n");
+    //printf("protection = %d\n", protection);
+    return (protection.kind == PROTexport) && !fbody;
+}
+
+// Determine if function goes into virtual function pointer table
+
+bool FuncDeclaration::isVirtual()
+{
+    if (toAliasFunc() != this)
+        return toAliasFunc()->isVirtual();
+
+    Dsymbol *p = toParent();
+#if 0
+    printf("FuncDeclaration::isVirtual(%s)\n", toChars());
+    printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd);
+    printf("result is %d\n",
+        isMember() &&
+        !(isStatic() || protection == PROTprivate || protection == PROTpackage) &&
+        p->isClassDeclaration() &&
+        !(p->isInterfaceDeclaration() && isFinalFunc()));
+#endif
+    return isMember() &&
+        !(isStatic() || protection.kind == PROTprivate || protection.kind == PROTpackage) &&
+        p->isClassDeclaration() &&
+        !(p->isInterfaceDeclaration() && isFinalFunc());
+}
+
+// Determine if a function is pedantically virtual
+
+bool FuncDeclaration::isVirtualMethod()
+{
+    if (toAliasFunc() != this)
+        return toAliasFunc()->isVirtualMethod();
+
+    //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
+    if (!isVirtual())
+        return false;
+    // If it's a final method, and does not override anything, then it is not virtual
+    if (isFinalFunc() && foverrides.dim == 0)
+    {
+        return false;
+    }
+    return true;
+}
+
+bool FuncDeclaration::isFinalFunc()
+{
+    if (toAliasFunc() != this)
+        return toAliasFunc()->isFinalFunc();
+
+    ClassDeclaration *cd;
+#if 0
+    printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration::isFinal());
+    printf("%p %d %d %d\n", isMember(), isStatic(), Declaration::isFinal(), ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal));
+    printf("result is %d\n",
+        isMember() &&
+        (Declaration::isFinal() ||
+         ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)));
+    if (cd)
+        printf("\tmember of %s\n", cd->toChars());
+#endif
+    return isMember() &&
+        (Declaration::isFinal() ||
+         ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal));
+}
+
+bool FuncDeclaration::isCodeseg()
+{
+    return true;                // functions are always in the code segment
+}
+
+bool FuncDeclaration::isOverloadable()
+{
+    return true;                // functions can be overloaded
+}
+
+PURE FuncDeclaration::isPure()
+{
+    //printf("FuncDeclaration::isPure() '%s'\n", toChars());
+    assert(type->ty == Tfunction);
+    TypeFunction *tf = (TypeFunction *)type;
+    if (flags & FUNCFLAGpurityInprocess)
+        setImpure();
+    if (tf->purity == PUREfwdref)
+        tf->purityLevel();
+    PURE purity = tf->purity;
+    if (purity > PUREweak && isNested())
+        purity = PUREweak;
+    if (purity > PUREweak && needThis())
+    {
+        // The attribute of the 'this' reference affects purity strength
+        if (type->mod & MODimmutable)
+            ;
+        else if (type->mod & (MODconst | MODwild) && purity >= PUREconst)
+            purity = PUREconst;
+        else
+            purity = PUREweak;
+    }
+    tf->purity = purity;
+    // ^ This rely on the current situation that every FuncDeclaration has a
+    //   unique TypeFunction.
+    return purity;
+}
+
+PURE FuncDeclaration::isPureBypassingInference()
+{
+    if (flags & FUNCFLAGpurityInprocess)
+        return PUREfwdref;
+    else
+        return isPure();
+}
+
+/**************************************
+ * The function is doing something impure,
+ * so mark it as impure.
+ * If there's a purity error, return true.
+ */
+bool FuncDeclaration::setImpure()
+{
+    if (flags & FUNCFLAGpurityInprocess)
+    {
+        flags &= ~FUNCFLAGpurityInprocess;
+        if (fes)
+            fes->func->setImpure();
+    }
+    else if (isPure())
+        return true;
+    return false;
+}
+
+bool FuncDeclaration::isSafe()
+{
+    assert(type->ty == Tfunction);
+    if (flags & FUNCFLAGsafetyInprocess)
+        setUnsafe();
+    return ((TypeFunction *)type)->trust == TRUSTsafe;
+}
+
+bool FuncDeclaration::isSafeBypassingInference()
+{
+    return !(flags & FUNCFLAGsafetyInprocess) && isSafe();
+}
+
+bool FuncDeclaration::isTrusted()
+{
+    assert(type->ty == Tfunction);
+    if (flags & FUNCFLAGsafetyInprocess)
+        setUnsafe();
+    return ((TypeFunction *)type)->trust == TRUSTtrusted;
+}
+
+/**************************************
+ * The function is doing something unsave,
+ * so mark it as unsafe.
+ * If there's a safe error, return true.
+ */
+bool FuncDeclaration::setUnsafe()
+{
+    if (flags & FUNCFLAGsafetyInprocess)
+    {
+        flags &= ~FUNCFLAGsafetyInprocess;
+        ((TypeFunction *)type)->trust = TRUSTsystem;
+        if (fes)
+            fes->func->setUnsafe();
+    }
+    else if (isSafe())
+        return true;
+    return false;
+}
+
+bool FuncDeclaration::isNogc()
+{
+    assert(type->ty == Tfunction);
+    if (flags & FUNCFLAGnogcInprocess)
+        setGC();
+    return ((TypeFunction *)type)->isnogc;
+}
+
+bool FuncDeclaration::isNogcBypassingInference()
+{
+    return !(flags & FUNCFLAGnogcInprocess) && isNogc();
+}
+
+/**************************************
+ * The function is doing something that may allocate with the GC,
+ * so mark it as not nogc (not no-how).
+ * Returns:
+ *      true if function is marked as @nogc, meaning a user error occurred
+ */
+bool FuncDeclaration::setGC()
+{
+    if (flags & FUNCFLAGnogcInprocess)
+    {
+        flags &= ~FUNCFLAGnogcInprocess;
+        ((TypeFunction *)type)->isnogc = false;
+        if (fes)
+            fes->func->setGC();
+    }
+    else if (isNogc())
+        return true;
+    return false;
+}
+
+/**************************************
+ * Returns an indirect type one step from t.
+ */
+
+Type *getIndirection(Type *t)
+{
+    t = t->baseElemOf();
+    if (t->ty == Tarray || t->ty == Tpointer)
+        return t->nextOf()->toBasetype();
+    if (t->ty == Taarray || t->ty == Tclass)
+        return t;
+    if (t->ty == Tstruct)
+        return t->hasPointers() ? t : NULL; // TODO
+
+    // should consider TypeDelegate?
+    return NULL;
+}
+
+/**************************************
+ * Returns true if memory reachable through a reference B to a value of type tb,
+ * which has been constructed with a reference A to a value of type ta
+ * available, can alias memory reachable from A based on the types involved
+ * (either directly or via any number of indirections).
+ *
+ * Note that this relation is not symmetric in the two arguments. For example,
+ * a const(int) reference can point to a pre-existing int, but not the other
+ * way round.
+ */
+bool traverseIndirections(Type *ta, Type *tb, void *p = NULL, bool reversePass = false)
+{
+    Type *source = ta;
+    Type *target = tb;
+    if (reversePass)
+    {
+        source = tb;
+        target = ta;
+    }
+
+    if (source->constConv(target))
+        return true;
+    else if (target->ty == Tvoid && MODimplicitConv(source->mod, target->mod))
+        return true;
+
+    // No direct match, so try breaking up one of the types (starting with tb).
+    Type *tbb = tb->toBasetype()->baseElemOf();
+    if (tbb != tb)
+        return traverseIndirections(ta, tbb, p, reversePass);
+
+    // context date to detect circular look up
+    struct Ctxt
+    {
+        Ctxt *prev;
+        Type *type;
+    };
+    Ctxt *ctxt = (Ctxt *)p;
+
+    if (tb->ty == Tclass || tb->ty == Tstruct)
+    {
+        for (Ctxt *c = ctxt; c; c = c->prev)
+            if (tb == c->type) return false;
+        Ctxt c;
+        c.prev = ctxt;
+        c.type = tb;
+
+        AggregateDeclaration *sym = tb->toDsymbol(NULL)->isAggregateDeclaration();
+        for (size_t i = 0; i < sym->fields.dim; i++)
+        {
+            VarDeclaration *v = sym->fields[i];
+            Type *tprmi = v->type->addMod(tb->mod);
+            //printf("\ttb = %s, tprmi = %s\n", tb->toChars(), tprmi->toChars());
+            if (traverseIndirections(ta, tprmi, &c, reversePass))
+                return true;
+        }
+    }
+    else if (tb->ty == Tarray || tb->ty == Taarray || tb->ty == Tpointer)
+    {
+        Type *tind = tb->nextOf();
+        if (traverseIndirections(ta, tind, ctxt, reversePass))
+            return true;
+    }
+    else if (tb->hasPointers())
+    {
+        // FIXME: function pointer/delegate types should be considered.
+        return true;
+    }
+
+    // Still no match, so try breaking up ta if we have note done so yet.
+    if (!reversePass)
+        return traverseIndirections(tb, ta, ctxt, true);
+
+    return false;
+}
+
+/********************************************
+ * Returns true if the function return value has no indirection
+ * which comes from the parameters.
+ */
+
+bool FuncDeclaration::isolateReturn()
+{
+    assert(type->ty == Tfunction);
+    TypeFunction *tf = (TypeFunction *)type;
+    assert(tf->next);
+
+    Type *treti = tf->next;
+    treti = tf->isref ? treti : getIndirection(treti);
+    if (!treti)
+        return true;    // target has no mutable indirection
+    return parametersIntersect(treti);
+}
+
+/********************************************
+ * Returns true if an object typed t can have indirections
+ * which come from the parameters.
+ */
+
+bool FuncDeclaration::parametersIntersect(Type *t)
+{
+    assert(t);
+    if (!isPureBypassingInference() || isNested())
+        return false;
+
+    assert(type->ty == Tfunction);
+    TypeFunction *tf = (TypeFunction *)type;
+
+    //printf("parametersIntersect(%s) t = %s\n", tf->toChars(), t->toChars());
+
+    size_t dim = Parameter::dim(tf->parameters);
+    for (size_t i = 0; i < dim; i++)
+    {
+        Parameter *fparam = Parameter::getNth(tf->parameters, i);
+        if (!fparam->type)
+            continue;
+        Type *tprmi = (fparam->storageClass & (STClazy | STCout | STCref))
+                ? fparam->type : getIndirection(fparam->type);
+        if (!tprmi)
+            continue;   // there is no mutable indirection
+
+        //printf("\t[%d] tprmi = %d %s\n", i, tprmi->ty, tprmi->toChars());
+        if (traverseIndirections(tprmi, t))
+            return false;
+    }
+    if (AggregateDeclaration *ad = isCtorDeclaration() ? NULL : isThis())
+    {
+        Type *tthis = ad->getType()->addMod(tf->mod);
+        //printf("\ttthis = %s\n", tthis->toChars());
+        if (traverseIndirections(tthis, t))
+            return false;
+    }
+
+    return true;
+}
+
+/****************************************
+ * Determine if function needs a static frame pointer.
+ * Returns:
+ *  `true` if function is really nested within other function.
+ * Contracts:
+ *  If isNested() returns true, isThis() should return false.
+ */
+bool FuncDeclaration::isNested()
+{
+    FuncDeclaration *f = toAliasFunc();
+    //printf("\ttoParent2() = '%s'\n", f->toParent2()->toChars());
+    return ((f->storage_class & STCstatic) == 0) &&
+           (f->linkage == LINKd) &&
+           (f->toParent2()->isFuncDeclaration() != NULL);
+}
+
+/****************************************
+ * Determine if function is a non-static member function
+ * that has an implicit 'this' expression.
+ * Returns:
+ *  The aggregate it is a member of, or null.
+ * Contracts:
+ *  If isThis() returns true, isNested() should return false.
+ */
+AggregateDeclaration *FuncDeclaration::isThis()
+{
+    //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
+    AggregateDeclaration *ad = (storage_class & STCstatic) ? NULL : isMember2();
+    //printf("-FuncDeclaration::isThis() %p\n", ad);
+    return ad;
+}
+
+bool FuncDeclaration::needThis()
+{
+    //printf("FuncDeclaration::needThis() '%s'\n", toChars());
+    return toAliasFunc()->isThis() != NULL;
+}
+
+bool FuncDeclaration::addPreInvariant()
+{
+    AggregateDeclaration *ad = isThis();
+    ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL;
+    return (ad && !(cd && cd->isCPPclass()) &&
+            global.params.useInvariants &&
+            (protection.kind == PROTprotected || protection.kind == PROTpublic || protection.kind == PROTexport) &&
+            !naked);
+}
+
+bool FuncDeclaration::addPostInvariant()
+{
+    AggregateDeclaration *ad = isThis();
+    ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL;
+    return (ad && !(cd && cd->isCPPclass()) &&
+            ad->inv &&
+            global.params.useInvariants &&
+            (protection.kind == PROTprotected || protection.kind == PROTpublic || protection.kind == PROTexport) &&
+            !naked);
+}
+
+/********************************************************
+ * Generate Expression to call the invariant.
+ * Input:
+ *      ad      aggregate with the invariant
+ *      vthis   variable with 'this'
+ *      direct  call invariant directly
+ * Returns:
+ *      void expression that calls the invariant
+ */
+Expression *addInvariant(Loc loc, Scope *sc, AggregateDeclaration *ad, VarDeclaration *vthis, bool direct)
+{
+    Expression *e = NULL;
+    if (direct)
+    {
+        // Call invariant directly only if it exists
+        FuncDeclaration *inv = ad->inv;
+        ClassDeclaration *cd = ad->isClassDeclaration();
+
+        while (!inv && cd)
+        {
+            cd = cd->baseClass;
+            if (!cd)
+                break;
+            inv = cd->inv;
+        }
+        if (inv)
+        {
+        #if 1
+            // Workaround for bugzilla 13394: For the correct mangling,
+            // run attribute inference on inv if needed.
+            inv->functionSemantic();
+        #endif
+
+            //e = new DsymbolExp(Loc(), inv);
+            //e = new CallExp(Loc(), e);
+            //e = e->semantic(sc2);
+
+            /* Bugzilla 13113: Currently virtual invariant calls completely
+             * bypass attribute enforcement.
+             * Change the behavior of pre-invariant call by following it.
+             */
+            e = new ThisExp(Loc());
+            e->type = vthis->type;
+            e = new DotVarExp(Loc(), e, inv, false);
+            e->type = inv->type;
+            e = new CallExp(Loc(), e);
+            e->type = Type::tvoid;
+        }
+    }
+    else
+    {
+    #if 1
+        // Workaround for bugzilla 13394: For the correct mangling,
+        // run attribute inference on inv if needed.
+        if (ad->isStructDeclaration() && ad->inv)
+            ad->inv->functionSemantic();
+    #endif
+
+        // Call invariant virtually
+        Expression *v = new ThisExp(Loc());
+        v->type = vthis->type;
+        if (ad->isStructDeclaration())
+            v = v->addressOf();
+        e = new StringExp(Loc(), (char *)"null this");
+        e = new AssertExp(loc, v, e);
+        e = semantic(e, sc);
+    }
+    return e;
+}
+
+/**********************************
+ * Generate a FuncDeclaration for a runtime library function.
+ */
+
+FuncDeclaration *FuncDeclaration::genCfunc(Parameters *fparams, Type *treturn, const char *name, StorageClass stc)
+{
+    return genCfunc(fparams, treturn, Identifier::idPool(name), stc);
+}
+
+FuncDeclaration *FuncDeclaration::genCfunc(Parameters *fparams, Type *treturn, Identifier *id, StorageClass stc)
+{
+    FuncDeclaration *fd;
+    TypeFunction *tf;
+    Dsymbol *s;
+    static DsymbolTable *st = NULL;
+
+    //printf("genCfunc(name = '%s')\n", id->toChars());
+    //printf("treturn\n\t"); treturn->print();
+
+    // See if already in table
+    if (!st)
+        st = new DsymbolTable();
+    s = st->lookup(id);
+    if (s)
+    {
+        fd = s->isFuncDeclaration();
+        assert(fd);
+        assert(fd->type->nextOf()->equals(treturn));
+    }
+    else
+    {
+        tf = new TypeFunction(fparams, treturn, 0, LINKc, stc);
+        fd = new FuncDeclaration(Loc(), Loc(), id, STCstatic, tf);
+        fd->protection = Prot(PROTpublic);
+        fd->linkage = LINKc;
+
+        st->insert(fd);
+    }
+    return fd;
+}
+
+/******************
+ * Check parameters and return type of D main() function.
+ * Issue error messages.
+ */
+void FuncDeclaration::checkDmain()
+{
+    TypeFunction *tf = (TypeFunction *)type;
+    const size_t nparams = Parameter::dim(tf->parameters);
+    bool argerr = false;
+    if (nparams == 1)
+    {
+        Parameter *fparam0 = Parameter::getNth(tf->parameters, 0);
+        Type *t = fparam0->type->toBasetype();
+        if (t->ty != Tarray ||
+            t->nextOf()->ty != Tarray ||
+            t->nextOf()->nextOf()->ty != Tchar ||
+            fparam0->storageClass & (STCout | STCref | STClazy))
+        {
+            argerr = true;
+        }
+    }
+
+    if (!tf->nextOf())
+        error("must return int or void");
+    else if (tf->nextOf()->ty != Tint32 && tf->nextOf()->ty != Tvoid)
+        error("must return int or void, not %s", tf->nextOf()->toChars());
+    else if (tf->varargs || nparams >= 2 || argerr)
+        error("parameters must be main() or main(string[] args)");
+}
+
+const char *FuncDeclaration::kind()
+{
+    return generated ? "generated function" : "function";
+}
+
+/*********************************************
+ * In the current function, we are calling 'this' function.
+ * 1. Check to see if the current function can call 'this' function, issue error if not.
+ * 2. If the current function is not the parent of 'this' function, then add
+ *    the current function to the list of siblings of 'this' function.
+ * 3. If the current function is a literal, and it's accessing an uplevel scope,
+ *    then mark it as a delegate.
+ * Returns true if error occurs.
+ */
+bool FuncDeclaration::checkNestedReference(Scope *sc, Loc loc)
+{
+    //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
+
+    if (FuncLiteralDeclaration *fld = this->isFuncLiteralDeclaration())
+    {
+        if (fld->tok == TOKreserved)
+        {
+            fld->tok = TOKfunction;
+            fld->vthis = NULL;
+        }
+    }
+
+    if (!parent || parent == sc->parent)
+        return false;
+    if (ident == Id::require || ident == Id::ensure)
+        return false;
+    if (!isThis() && !isNested())
+        return false;
+
+    // The current function
+    FuncDeclaration *fdthis = sc->parent->isFuncDeclaration();
+    if (!fdthis)
+        return false;   // out of function scope
+
+    Dsymbol *p = toParent2();
+
+    // Function literals from fdthis to p must be delegates
+    checkNestedRef(fdthis, p);
+
+    if (isNested())
+    {
+        // The function that this function is in
+        FuncDeclaration *fdv = p->isFuncDeclaration();
+        if (!fdv)
+            return false;
+        if (fdv == fdthis)
+            return false;
+
+        //printf("this = %s in [%s]\n", this->toChars(), this->loc.toChars());
+        //printf("fdv = %s in [%s]\n", fdv->toChars(), fdv->loc.toChars());
+        //printf("fdthis = %s in [%s]\n", fdthis->toChars(), fdthis->loc.toChars());
+
+        // Add this function to the list of those which called us
+        if (fdthis != this)
+        {
+            bool found = false;
+            for (size_t i = 0; i < siblingCallers.dim; ++i)
+            {
+                if (siblingCallers[i] == fdthis)
+                    found = true;
+            }
+            if (!found)
+            {
+                //printf("\tadding sibling %s\n", fdthis->toPrettyChars());
+                if (!sc->intypeof && !(sc->flags & SCOPEcompile))
+                    siblingCallers.push(fdthis);
+            }
+        }
+
+        int lv = fdthis->getLevel(loc, sc, fdv);
+        if (lv == -2)
+            return true;    // error
+        if (lv == -1)
+            return false;   // downlevel call
+        if (lv == 0)
+            return false;   // same level call
+        // Uplevel call
+    }
+    return false;
+}
+
+/* For all functions between outerFunc and f, mark them as needing
+ * a closure.
+ */
+void markAsNeedingClosure(Dsymbol *f, FuncDeclaration *outerFunc)
+{
+    for (Dsymbol *sx = f; sx && sx != outerFunc; sx = sx->parent)
+    {
+        FuncDeclaration *fy = sx->isFuncDeclaration();
+        if (fy && fy->closureVars.dim)
+        {
+            /* fy needs a closure if it has closureVars[],
+             * because the frame pointer in the closure will be accessed.
+             */
+            fy->requiresClosure = true;
+        }
+    }
+}
+
+
+/* Given a nested function f inside a function outerFunc, check
+ * if any sibling callers of f have escaped. If so, mark
+ * all the enclosing functions as needing closures.
+ * Return true if any closures were detected.
+ * This is recursive: we need to check the callers of our siblings.
+ * Note that nested functions can only call lexically earlier nested
+ * functions, so loops are impossible.
+ */
+bool checkEscapingSiblings(FuncDeclaration *f, FuncDeclaration *outerFunc, void *p = NULL)
+{
+    struct PrevSibling
+    {
+        PrevSibling *p;
+        FuncDeclaration *f;
+    };
+
+    PrevSibling ps;
+    ps.p = (PrevSibling *)p;
+    ps.f = f;
+
+    //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f->toChars(), outerFunc->toChars());
+    bool bAnyClosures = false;
+    for (size_t i = 0; i < f->siblingCallers.dim; ++i)
+    {
+        FuncDeclaration *g = f->siblingCallers[i];
+        if (g->isThis() || g->tookAddressOf)
+        {
+            markAsNeedingClosure(g, outerFunc);
+            bAnyClosures = true;
+        }
+
+        PrevSibling *prev = (PrevSibling *)p;
+        while (1)
+        {
+            if (!prev)
+            {
+                bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
+                break;
+            }
+            if (prev->f == g)
+                break;
+            prev = prev->p;
+        }
+    }
+    //printf("\t%d\n", bAnyClosures);
+    return bAnyClosures;
+}
+
+
+/*******************************
+ * Look at all the variables in this function that are referenced
+ * by nested functions, and determine if a closure needs to be
+ * created for them.
+ */
+
+bool FuncDeclaration::needsClosure()
+{
+    /* Need a closure for all the closureVars[] if any of the
+     * closureVars[] are accessed by a
+     * function that escapes the scope of this function.
+     * We take the conservative approach and decide that a function needs
+     * a closure if it:
+     * 1) is a virtual function
+     * 2) has its address taken
+     * 3) has a parent that escapes
+     * 4) calls another nested function that needs a closure
+     *
+     * Note that since a non-virtual function can be called by
+     * a virtual one, if that non-virtual function accesses a closure
+     * var, the closure still has to be taken. Hence, we check for isThis()
+     * instead of isVirtual(). (thanks to David Friedman)
+     *
+     * When the function returns a local struct or class, `requiresClosure`
+     * is already set to `true` upon entering this function when the
+     * struct/class refers to a local variable and a closure is needed.
+     */
+
+    //printf("FuncDeclaration::needsClosure() %s\n", toChars());
+
+    if (requiresClosure)
+        goto Lyes;
+
+    for (size_t i = 0; i < closureVars.dim; i++)
+    {
+        VarDeclaration *v = closureVars[i];
+        //printf("\tv = %s\n", v->toChars());
+
+        for (size_t j = 0; j < v->nestedrefs.dim; j++)
+        {
+            FuncDeclaration *f = v->nestedrefs[j];
+            assert(f != this);
+
+            //printf("\t\tf = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf);
+
+            /* Look to see if f escapes. We consider all parents of f within
+             * this, and also all siblings which call f; if any of them escape,
+             * so does f.
+             * Mark all affected functions as requiring closures.
+             */
+            for (Dsymbol *s = f; s && s != this; s = s->parent)
+            {
+                FuncDeclaration *fx = s->isFuncDeclaration();
+                if (!fx)
+                    continue;
+                if (fx->isThis() || fx->tookAddressOf)
+                {
+                    //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx->toChars(), fx->isVirtual(), fx->isThis(), fx->tookAddressOf);
+
+                    /* Mark as needing closure any functions between this and f
+                     */
+                    markAsNeedingClosure( (fx == f) ? fx->parent : fx, this);
+
+                    requiresClosure = true;
+                }
+
+                /* We also need to check if any sibling functions that
+                 * called us, have escaped. This is recursive: we need
+                 * to check the callers of our siblings.
+                 */
+                if (checkEscapingSiblings(fx, this))
+                    requiresClosure = true;
+
+                /* Bugzilla 12406: Iterate all closureVars to mark all descendant
+                 * nested functions that access to the closing context of this funciton.
+                 */
+            }
+        }
+    }
+    if (requiresClosure)
+        goto Lyes;
+
+    return false;
+
+Lyes:
+    //printf("\tneeds closure\n");
+    return true;
+}
+
+/***********************************************
+ * Check that the function contains any closure.
+ * If it's @nogc, report suitable errors.
+ * This is mostly consistent with FuncDeclaration::needsClosure().
+ *
+ * Returns:
+ *      true if any errors occur.
+ */
+bool FuncDeclaration::checkClosure()
+{
+    if (!needsClosure())
+        return false;
+
+    if (setGC())
+    {
+        error("is @nogc yet allocates closures with the GC");
+        if (global.gag)     // need not report supplemental errors
+            return true;
+    }
+    else
+    {
+        printGCUsage(loc, "using closure causes GC allocation");
+        return false;
+    }
+
+    FuncDeclarations a;
+    for (size_t i = 0; i < closureVars.dim; i++)
+    {
+        VarDeclaration *v = closureVars[i];
+
+        for (size_t j = 0; j < v->nestedrefs.dim; j++)
+        {
+            FuncDeclaration *f = v->nestedrefs[j];
+            assert(f != this);
+
+            for (Dsymbol *s = f; s && s != this; s = s->parent)
+            {
+                FuncDeclaration *fx = s->isFuncDeclaration();
+                if (!fx)
+                    continue;
+                if (fx->isThis() || fx->tookAddressOf)
+                    goto Lfound;
+                if (checkEscapingSiblings(fx, this))
+                    goto Lfound;
+            }
+            continue;
+
+        Lfound:
+            for (size_t k = 0; ; k++)
+            {
+                if (k == a.dim)
+                {
+                    a.push(f);
+                    ::errorSupplemental(f->loc, "%s closes over variable %s at %s",
+                        f->toPrettyChars(), v->toChars(), v->loc.toChars());
+                    break;
+                }
+                if (a[k] == f)
+                    break;
+            }
+            continue;
+        }
+    }
+
+    return true;
+}
+
+/***********************************************
+ * Determine if function's variables are referenced by a function
+ * nested within it.
+ */
+
+bool FuncDeclaration::hasNestedFrameRefs()
+{
+    if (closureVars.dim)
+        return true;
+
+    /* If a virtual function has contracts, assume its variables are referenced
+     * by those contracts, even if they aren't. Because they might be referenced
+     * by the overridden or overriding function's contracts.
+     * This can happen because frequire and fensure are implemented as nested functions,
+     * and they can be called directly by an overriding function and the overriding function's
+     * context had better match, or Bugzilla 7335 will bite.
+     */
+    if (fdrequire || fdensure)
+        return true;
+
+    if (foverrides.dim && isVirtualMethod())
+    {
+        for (size_t i = 0; i < foverrides.dim; i++)
+        {
+            FuncDeclaration *fdv = foverrides[i];
+            if (fdv->hasNestedFrameRefs())
+                return true;
+        }
+    }
+
+    return false;
+}
+
+/*********************************************
+ * Return the function's parameter list, and whether
+ * it is variadic or not.
+ */
+
+Parameters *FuncDeclaration::getParameters(int *pvarargs)
+{
+    Parameters *fparameters = NULL;
+    int fvarargs = 0;
+
+    if (type)
+    {
+        assert(type->ty == Tfunction);
+        TypeFunction *fdtype = (TypeFunction *)type;
+        fparameters = fdtype->parameters;
+        fvarargs = fdtype->varargs;
+    }
+    if (pvarargs)
+        *pvarargs = fvarargs;
+    return fparameters;
+}
+
+
+/****************************** FuncAliasDeclaration ************************/
+
+// Used as a way to import a set of functions from another scope into this one.
+
+FuncAliasDeclaration::FuncAliasDeclaration(Identifier *ident, FuncDeclaration *funcalias, bool hasOverloads)
+    : FuncDeclaration(funcalias->loc, funcalias->endloc, ident,
+        funcalias->storage_class, funcalias->type)
+{
+    assert(funcalias != this);
+    this->funcalias = funcalias;
+
+    this->hasOverloads = hasOverloads;
+    if (hasOverloads)
+    {
+        if (FuncAliasDeclaration *fad = funcalias->isFuncAliasDeclaration())
+            this->hasOverloads = fad->hasOverloads;
+    }
+    else
+    {   // for internal use
+        assert(!funcalias->isFuncAliasDeclaration());
+        this->hasOverloads = false;
+    }
+    userAttribDecl = funcalias->userAttribDecl;
+}
+
+const char *FuncAliasDeclaration::kind()
+{
+    return "function alias";
+}
+
+FuncDeclaration *FuncAliasDeclaration::toAliasFunc()
+{
+    return funcalias->toAliasFunc();
+}
+
+
+/****************************** FuncLiteralDeclaration ************************/
+
+FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type,
+        TOK tok, ForeachStatement *fes, Identifier *id)
+    : FuncDeclaration(loc, endloc, NULL, STCundefined, type)
+{
+    this->ident = id ? id : Id::empty;
+    this->tok = tok;
+    this->fes = fes;
+    this->treq = NULL;
+    this->deferToObj = false;
+    //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars());
+}
+
+Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
+    assert(!s);
+    FuncLiteralDeclaration *f = new FuncLiteralDeclaration(loc, endloc,
+        type->syntaxCopy(), tok, fes, ident);
+    f->treq = treq;     // don't need to copy
+    return FuncDeclaration::syntaxCopy(f);
+}
+
+bool FuncLiteralDeclaration::isNested()
+{
+    //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
+    return (tok != TOKfunction) && !isThis();
+}
+
+AggregateDeclaration *FuncLiteralDeclaration::isThis()
+{
+    //printf("FuncLiteralDeclaration::isThis() '%s'\n", toChars());
+    return tok == TOKdelegate ? FuncDeclaration::isThis() : NULL;
+}
+
+bool FuncLiteralDeclaration::isVirtual()
+{
+    return false;
+}
+
+bool FuncLiteralDeclaration::addPreInvariant()
+{
+    return false;
+}
+
+bool FuncLiteralDeclaration::addPostInvariant()
+{
+    return false;
+}
+
+/*******************************
+ * Modify all expression type of return statements to tret.
+ *
+ * On function literals, return type may be modified based on the context type
+ * after its semantic3 is done, in FuncExp::implicitCastTo.
+ *
+ *  A function() dg = (){ return new B(); } // OK if is(B : A) == true
+ *
+ * If B to A conversion is convariant that requires offseet adjusting,
+ * all return statements should be adjusted to return expressions typed A.
+ */
+void FuncLiteralDeclaration::modifyReturns(Scope *sc, Type *tret)
+{
+    class RetWalker : public StatementRewriteWalker
+    {
+    public:
+        Scope *sc;
+        Type *tret;
+        FuncLiteralDeclaration *fld;
+
+        void visit(ReturnStatement *s)
+        {
+            Expression *exp = s->exp;
+            if (exp && !exp->type->equals(tret))
+            {
+                s->exp = exp->castTo(sc, tret);
+            }
+        }
+    };
+
+    if (semanticRun < PASSsemantic3done)
+        return;
+
+    if (fes)
+        return;
+
+    RetWalker w;
+    w.sc = sc;
+    w.tret = tret;
+    w.fld = this;
+    fbody->accept(&w);
+
+    // Also update the inferred function type to match the new return type.
+    // This is required so the code generator does not try to cast the
+    // modified returns back to the original type.
+    if (inferRetType && type->nextOf() != tret)
+        ((TypeFunction *)type)->next = tret;
+}
+
+const char *FuncLiteralDeclaration::kind()
+{
+    // GCC requires the (char*) casts
+    return (tok != TOKfunction) ? (char*)"delegate" : (char*)"function";
+}
+
+const char *FuncLiteralDeclaration::toPrettyChars(bool QualifyTypes)
+{
+    if (parent)
+    {
+        TemplateInstance *ti = parent->isTemplateInstance();
+        if (ti)
+            return ti->tempdecl->toPrettyChars(QualifyTypes);
+    }
+    return Dsymbol::toPrettyChars(QualifyTypes);
+}
+
+/********************************* CtorDeclaration ****************************/
+
+CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type)
+    : FuncDeclaration(loc, endloc, Id::ctor, stc, type)
+{
+    //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars());
+}
+
+Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    CtorDeclaration *f = new CtorDeclaration(loc, endloc, storage_class, type->syntaxCopy());
+    return FuncDeclaration::syntaxCopy(f);
+}
+
+void CtorDeclaration::semantic(Scope *sc)
+{
+    //printf("CtorDeclaration::semantic() %s\n", toChars());
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    if (_scope)
+    {
+        sc = _scope;
+        _scope = NULL;
+    }
+
+    parent = sc->parent;
+    Dsymbol *p = toParent2();
+    AggregateDeclaration *ad = p->isAggregateDeclaration();
+    if (!ad)
+    {
+        ::error(loc, "constructor can only be a member of aggregate, not %s %s",
+            p->kind(), p->toChars());
+        type = Type::terror;
+        errors = true;
+        return;
+    }
+
+    sc = sc->push();
+    sc->stc &= ~STCstatic;              // not a static constructor
+    sc->flags |= SCOPEctor;
+
+    FuncDeclaration::semantic(sc);
+
+    sc->pop();
+
+    if (errors)
+        return;
+
+    TypeFunction *tf = (TypeFunction *)type;
+    assert(tf && tf->ty == Tfunction);
+
+    /* See if it's the default constructor
+     * But, template constructor should not become a default constructor.
+     */
+    if (ad && (!parent->isTemplateInstance() || parent->isTemplateMixin()))
+    {
+        const size_t dim = Parameter::dim(tf->parameters);
+
+        if (StructDeclaration *sd = ad->isStructDeclaration())
+        {
+            if (dim == 0 && tf->varargs == 0) // empty default ctor w/o any varargs
+            {
+                if (fbody || !(storage_class & STCdisable) || dim)
+                {
+                    error("default constructor for structs only allowed "
+                        "with @disable, no body, and no parameters");
+                    storage_class |= STCdisable;
+                    fbody = NULL;
+                }
+                sd->noDefaultCtor = true;
+            }
+            else if (dim == 0 && tf->varargs) // allow varargs only ctor
+            {
+            }
+            else if (dim && Parameter::getNth(tf->parameters, 0)->defaultArg)
+            {
+                // if the first parameter has a default argument, then the rest does as well
+                if (storage_class & STCdisable)
+                {
+                    deprecation("@disable'd constructor cannot have default "
+                                "arguments for all parameters.");
+                    deprecationSupplemental(loc, "Use @disable this(); if you want to disable default initialization.");
+                }
+                else
+                    deprecation("all parameters have default arguments, "
+                                "but structs cannot have default constructors.");
+            }
+
+        }
+        else if (dim == 0 && tf->varargs == 0)
+        {
+            ad->defaultCtor = this;
+        }
+    }
+}
+
+const char *CtorDeclaration::kind()
+{
+    return "constructor";
+}
+
+const char *CtorDeclaration::toChars()
+{
+    return (char *)"this";
+}
+
+bool CtorDeclaration::isVirtual()
+{
+    return false;
+}
+
+bool CtorDeclaration::addPreInvariant()
+{
+    return false;
+}
+
+bool CtorDeclaration::addPostInvariant()
+{
+    return (isThis() && vthis && global.params.useInvariants);
+}
+
+
+/********************************* PostBlitDeclaration ****************************/
+
+PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id)
+    : FuncDeclaration(loc, endloc, id, stc, NULL)
+{
+}
+
+Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
+    return FuncDeclaration::syntaxCopy(dd);
+}
+
+void PostBlitDeclaration::semantic(Scope *sc)
+{
+    //printf("PostBlitDeclaration::semantic() %s\n", toChars());
+    //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor);
+    //printf("stc = x%llx\n", sc->stc);
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    if (_scope)
+    {
+        sc = _scope;
+        _scope = NULL;
+    }
+
+    parent = sc->parent;
+    Dsymbol *p = toParent2();
+    StructDeclaration *ad = p->isStructDeclaration();
+    if (!ad)
+    {
+        ::error(loc, "postblit can only be a member of struct/union, not %s %s",
+            p->kind(), p->toChars());
+        type = Type::terror;
+        errors = true;
+        return;
+    }
+    if (ident == Id::postblit && semanticRun < PASSsemantic)
+        ad->postblits.push(this);
+    if (!type)
+        type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class);
+
+    sc = sc->push();
+    sc->stc &= ~STCstatic;              // not static
+    sc->linkage = LINKd;
+
+    FuncDeclaration::semantic(sc);
+
+    sc->pop();
+}
+
+bool PostBlitDeclaration::overloadInsert(Dsymbol *s)
+{
+    return false;       // cannot overload postblits
+}
+
+bool PostBlitDeclaration::addPreInvariant()
+{
+    return false;
+}
+
+bool PostBlitDeclaration::addPostInvariant()
+{
+    return (isThis() && vthis && global.params.useInvariants);
+}
+
+bool PostBlitDeclaration::isVirtual()
+{
+    return false;
+}
+
+/********************************* DtorDeclaration ****************************/
+
+DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc)
+    : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL)
+{
+}
+
+DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id)
+    : FuncDeclaration(loc, endloc, id, stc, NULL)
+{
+}
+
+Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    DtorDeclaration *dd = new DtorDeclaration(loc, endloc, storage_class, ident);
+    return FuncDeclaration::syntaxCopy(dd);
+}
+
+void DtorDeclaration::semantic(Scope *sc)
+{
+    //printf("DtorDeclaration::semantic() %s\n", toChars());
+    //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor);
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    if (_scope)
+    {
+        sc = _scope;
+        _scope = NULL;
+    }
+
+    parent = sc->parent;
+    Dsymbol *p = toParent2();
+    AggregateDeclaration *ad = p->isAggregateDeclaration();
+    if (!ad)
+    {
+        ::error(loc, "destructor can only be a member of aggregate, not %s %s",
+            p->kind(), p->toChars());
+        type = Type::terror;
+        errors = true;
+        return;
+    }
+    if (ident == Id::dtor && semanticRun < PASSsemantic)
+        ad->dtors.push(this);
+    if (!type)
+        type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class);
+
+    sc = sc->push();
+    sc->stc &= ~STCstatic;              // not a static destructor
+    if (sc->linkage != LINKcpp)
+        sc->linkage = LINKd;
+
+    FuncDeclaration::semantic(sc);
+
+    sc->pop();
+}
+
+bool DtorDeclaration::overloadInsert(Dsymbol *s)
+{
+    return false;       // cannot overload destructors
+}
+
+bool DtorDeclaration::addPreInvariant()
+{
+    return (isThis() && vthis && global.params.useInvariants);
+}
+
+bool DtorDeclaration::addPostInvariant()
+{
+    return false;
+}
+
+const char *DtorDeclaration::kind()
+{
+    return "destructor";
+}
+
+const char *DtorDeclaration::toChars()
+{
+    return (char *)"~this";
+}
+
+bool DtorDeclaration::isVirtual()
+{
+    // false so that dtor's don't get put into the vtbl[]
+    return false;
+}
+
+/********************************* StaticCtorDeclaration ****************************/
+
+StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
+    : FuncDeclaration(loc, endloc,
+      Identifier::generateId("_staticCtor"), STCstatic | stc, NULL)
+{
+}
+
+StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc)
+    : FuncDeclaration(loc, endloc,
+      Identifier::generateId(name), STCstatic | stc, NULL)
+{
+}
+
+Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    StaticCtorDeclaration *scd = new StaticCtorDeclaration(loc, endloc, storage_class);
+    return FuncDeclaration::syntaxCopy(scd);
+}
+
+void StaticCtorDeclaration::semantic(Scope *sc)
+{
+    //printf("StaticCtorDeclaration::semantic()\n");
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    if (_scope)
+    {
+        sc = _scope;
+        _scope = NULL;
+    }
+
+    parent = sc->parent;
+    Dsymbol *p = parent->pastMixin();
+    if (!p->isScopeDsymbol())
+    {
+        const char *s = (isSharedStaticCtorDeclaration() ? "shared " : "");
+        ::error(loc, "%sstatic constructor can only be member of module/aggregate/template, not %s %s",
+            s, p->kind(), p->toChars());
+        type = Type::terror;
+        errors = true;
+        return;
+    }
+    if (!type)
+        type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class);
+
+    /* If the static ctor appears within a template instantiation,
+     * it could get called multiple times by the module constructors
+     * for different modules. Thus, protect it with a gate.
+     */
+    if (isInstantiated() && semanticRun < PASSsemantic)
+    {
+        /* Add this prefix to the function:
+         *      static int gate;
+         *      if (++gate != 1) return;
+         * Note that this is not thread safe; should not have threads
+         * during static construction.
+         */
+        VarDeclaration *v = new VarDeclaration(Loc(), Type::tint32, Id::gate, NULL);
+        v->storage_class = STCtemp | (isSharedStaticCtorDeclaration() ? STCstatic : STCtls);
+        Statements *sa = new Statements();
+        Statement *s = new ExpStatement(Loc(), v);
+        sa->push(s);
+        Expression *e = new IdentifierExp(Loc(), v->ident);
+        e = new AddAssignExp(Loc(), e, new IntegerExp(1));
+        e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(1));
+        s = new IfStatement(Loc(), NULL, e, new ReturnStatement(Loc(), NULL), NULL, Loc());
+        sa->push(s);
+        if (fbody)
+            sa->push(fbody);
+        fbody = new CompoundStatement(Loc(), sa);
+    }
+
+    FuncDeclaration::semantic(sc);
+
+    // We're going to need ModuleInfo
+    Module *m = getModule();
+    if (!m)
+        m = sc->_module;
+    if (m)
+    {
+        m->needmoduleinfo = 1;
+        //printf("module1 %s needs moduleinfo\n", m->toChars());
+    }
+}
+
+AggregateDeclaration *StaticCtorDeclaration::isThis()
+{
+    return NULL;
+}
+
+bool StaticCtorDeclaration::isVirtual()
+{
+    return false;
+}
+
+bool StaticCtorDeclaration::hasStaticCtorOrDtor()
+{
+    return true;
+}
+
+bool StaticCtorDeclaration::addPreInvariant()
+{
+    return false;
+}
+
+bool StaticCtorDeclaration::addPostInvariant()
+{
+    return false;
+}
+
+/********************************* SharedStaticCtorDeclaration ****************************/
+
+SharedStaticCtorDeclaration::SharedStaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
+    : StaticCtorDeclaration(loc, endloc, "_sharedStaticCtor", stc)
+{
+}
+
+Dsymbol *SharedStaticCtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    SharedStaticCtorDeclaration *scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
+    return FuncDeclaration::syntaxCopy(scd);
+}
+
+/********************************* StaticDtorDeclaration ****************************/
+
+StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
+    : FuncDeclaration(loc, endloc,
+      Identifier::generateId("_staticDtor"), STCstatic | stc, NULL)
+{
+    vgate = NULL;
+}
+
+StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc)
+    : FuncDeclaration(loc, endloc,
+      Identifier::generateId(name), STCstatic | stc, NULL)
+{
+    vgate = NULL;
+}
+
+Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    StaticDtorDeclaration *sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
+    return FuncDeclaration::syntaxCopy(sdd);
+}
+
+void StaticDtorDeclaration::semantic(Scope *sc)
+{
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    if (_scope)
+    {
+        sc = _scope;
+        _scope = NULL;
+    }
+
+    parent = sc->parent;
+    Dsymbol *p = parent->pastMixin();
+    if (!p->isScopeDsymbol())
+    {
+        const char *s = (isSharedStaticDtorDeclaration() ? "shared " : "");
+        ::error(loc, "%sstatic destructor can only be member of module/aggregate/template, not %s %s",
+            s, p->kind(), p->toChars());
+        type = Type::terror;
+        errors = true;
+        return;
+    }
+    if (!type)
+        type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class);
+
+    /* If the static ctor appears within a template instantiation,
+     * it could get called multiple times by the module constructors
+     * for different modules. Thus, protect it with a gate.
+     */
+    if (isInstantiated() && semanticRun < PASSsemantic)
+    {
+        /* Add this prefix to the function:
+         *      static int gate;
+         *      if (--gate != 0) return;
+         * Increment gate during constructor execution.
+         * Note that this is not thread safe; should not have threads
+         * during static destruction.
+         */
+        VarDeclaration *v = new VarDeclaration(Loc(), Type::tint32, Id::gate, NULL);
+        v->storage_class = STCtemp | (isSharedStaticDtorDeclaration() ? STCstatic : STCtls);
+        Statements *sa = new Statements();
+        Statement *s = new ExpStatement(Loc(), v);
+        sa->push(s);
+        Expression *e = new IdentifierExp(Loc(), v->ident);
+        e = new AddAssignExp(Loc(), e, new IntegerExp(-1));
+        e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(0));
+        s = new IfStatement(Loc(), NULL, e, new ReturnStatement(Loc(), NULL), NULL, Loc());
+        sa->push(s);
+        if (fbody)
+            sa->push(fbody);
+        fbody = new CompoundStatement(Loc(), sa);
+        vgate = v;
+    }
+
+    FuncDeclaration::semantic(sc);
+
+    // We're going to need ModuleInfo
+    Module *m = getModule();
+    if (!m)
+        m = sc->_module;
+    if (m)
+    {
+        m->needmoduleinfo = 1;
+        //printf("module2 %s needs moduleinfo\n", m->toChars());
+    }
+}
+
+AggregateDeclaration *StaticDtorDeclaration::isThis()
+{
+    return NULL;
+}
+
+bool StaticDtorDeclaration::isVirtual()
+{
+    return false;
+}
+
+bool StaticDtorDeclaration::hasStaticCtorOrDtor()
+{
+    return true;
+}
+
+bool StaticDtorDeclaration::addPreInvariant()
+{
+    return false;
+}
+
+bool StaticDtorDeclaration::addPostInvariant()
+{
+    return false;
+}
+
+/********************************* SharedStaticDtorDeclaration ****************************/
+
+SharedStaticDtorDeclaration::SharedStaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
+    : StaticDtorDeclaration(loc, endloc, "_sharedStaticDtor", stc)
+{
+}
+
+Dsymbol *SharedStaticDtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    SharedStaticDtorDeclaration *sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
+    return FuncDeclaration::syntaxCopy(sdd);
+}
+
+/********************************* InvariantDeclaration ****************************/
+
+InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id)
+    : FuncDeclaration(loc, endloc,
+                      id ? id : Identifier::generateId("__invariant"),
+                      stc, NULL)
+{
+}
+
+Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    InvariantDeclaration *id = new InvariantDeclaration(loc, endloc, storage_class);
+    return FuncDeclaration::syntaxCopy(id);
+}
+
+void InvariantDeclaration::semantic(Scope *sc)
+{
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    if (_scope)
+    {
+        sc = _scope;
+        _scope = NULL;
+    }
+
+    parent = sc->parent;
+    Dsymbol *p = parent->pastMixin();
+    AggregateDeclaration *ad = p->isAggregateDeclaration();
+    if (!ad)
+    {
+        ::error(loc, "invariant can only be a member of aggregate, not %s %s",
+            p->kind(), p->toChars());
+        type = Type::terror;
+        errors = true;
+        return;
+    }
+    if (ident != Id::classInvariant &&
+        semanticRun < PASSsemantic &&
+        !ad->isUnionDeclaration()           // users are on their own with union fields
+       )
+        ad->invs.push(this);
+    if (!type)
+        type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class);
+
+    sc = sc->push();
+    sc->stc &= ~STCstatic;              // not a static invariant
+    sc->stc |= STCconst;                // invariant() is always const
+    sc->flags = (sc->flags & ~SCOPEcontract) | SCOPEinvariant;
+    sc->linkage = LINKd;
+
+    FuncDeclaration::semantic(sc);
+
+    sc->pop();
+}
+
+bool InvariantDeclaration::isVirtual()
+{
+    return false;
+}
+
+bool InvariantDeclaration::addPreInvariant()
+{
+    return false;
+}
+
+bool InvariantDeclaration::addPostInvariant()
+{
+    return false;
+}
+
+/********************************* UnitTestDeclaration ****************************/
+
+/*******************************
+ * Generate unique unittest function Id so we can have multiple
+ * instances per module.
+ */
+
+static Identifier *unitTestId(Loc loc)
+{
+    OutBuffer buf;
+    buf.printf("__unittestL%u_", loc.linnum);
+    return Identifier::generateId(buf.peekString());
+}
+
+UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc)
+    : FuncDeclaration(loc, endloc, unitTestId(loc), stc, NULL)
+{
+    this->codedoc = codedoc;
+}
+
+Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    UnitTestDeclaration *utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
+    return FuncDeclaration::syntaxCopy(utd);
+}
+
+void UnitTestDeclaration::semantic(Scope *sc)
+{
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    if (_scope)
+    {
+        sc = _scope;
+        _scope = NULL;
+    }
+
+    protection = sc->protection;
+
+    parent = sc->parent;
+    Dsymbol *p = parent->pastMixin();
+    if (!p->isScopeDsymbol())
+    {
+        ::error(loc, "unittest can only be a member of module/aggregate/template, not %s %s",
+            p->kind(), p->toChars());
+        type = Type::terror;
+        errors = true;
+        return;
+    }
+
+    if (global.params.useUnitTests)
+    {
+        if (!type)
+            type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class);
+        Scope *sc2 = sc->push();
+        sc2->linkage = LINKd;
+        FuncDeclaration::semantic(sc2);
+        sc2->pop();
+    }
+
+#if 0
+    // We're going to need ModuleInfo even if the unit tests are not
+    // compiled in, because other modules may import this module and refer
+    // to this ModuleInfo.
+    // (This doesn't make sense to me?)
+    Module *m = getModule();
+    if (!m)
+        m = sc->_module;
+    if (m)
+    {
+        //printf("module3 %s needs moduleinfo\n", m->toChars());
+        m->needmoduleinfo = 1;
+    }
+#endif
+}
+
+AggregateDeclaration *UnitTestDeclaration::isThis()
+{
+    return NULL;
+}
+
+bool UnitTestDeclaration::isVirtual()
+{
+    return false;
+}
+
+bool UnitTestDeclaration::addPreInvariant()
+{
+    return false;
+}
+
+bool UnitTestDeclaration::addPostInvariant()
+{
+    return false;
+}
+
+/********************************* NewDeclaration ****************************/
+
+NewDeclaration::NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *fparams, int varargs)
+    : FuncDeclaration(loc, endloc, Id::classNew, STCstatic | stc, NULL)
+{
+    this->parameters = fparams;
+    this->varargs = varargs;
+}
+
+Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    NewDeclaration *f = new NewDeclaration(loc, endloc,
+        storage_class, Parameter::arraySyntaxCopy(parameters), varargs);
+    return FuncDeclaration::syntaxCopy(f);
+}
+
+void NewDeclaration::semantic(Scope *sc)
+{
+    //printf("NewDeclaration::semantic()\n");
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    if (_scope)
+    {
+        sc = _scope;
+        _scope = NULL;
+    }
+
+    parent = sc->parent;
+    Dsymbol *p = parent->pastMixin();
+    if (!p->isAggregateDeclaration())
+    {
+        ::error(loc, "allocator can only be a member of aggregate, not %s %s",
+            p->kind(), p->toChars());
+        type = Type::terror;
+        errors = true;
+        return;
+    }
+    Type *tret = Type::tvoid->pointerTo();
+    if (!type)
+        type = new TypeFunction(parameters, tret, varargs, LINKd, storage_class);
+
+    type = type->semantic(loc, sc);
+    assert(type->ty == Tfunction);
+
+    // Check that there is at least one argument of type size_t
+    TypeFunction *tf = (TypeFunction *)type;
+    if (Parameter::dim(tf->parameters) < 1)
+    {
+        error("at least one argument of type size_t expected");
+    }
+    else
+    {
+        Parameter *fparam = Parameter::getNth(tf->parameters, 0);
+        if (!fparam->type->equals(Type::tsize_t))
+            error("first argument must be type size_t, not %s", fparam->type->toChars());
+    }
+
+    FuncDeclaration::semantic(sc);
+}
+
+const char *NewDeclaration::kind()
+{
+    return "allocator";
+}
+
+bool NewDeclaration::isVirtual()
+{
+    return false;
+}
+
+bool NewDeclaration::addPreInvariant()
+{
+    return false;
+}
+
+bool NewDeclaration::addPostInvariant()
+{
+    return false;
+}
+
+/********************************* DeleteDeclaration ****************************/
+
+DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *fparams)
+    : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic | stc, NULL)
+{
+    this->parameters = fparams;
+}
+
+Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    DeleteDeclaration *f = new DeleteDeclaration(loc, endloc,
+            storage_class, Parameter::arraySyntaxCopy(parameters));
+    return FuncDeclaration::syntaxCopy(f);
+}
+
+void DeleteDeclaration::semantic(Scope *sc)
+{
+    //printf("DeleteDeclaration::semantic()\n");
+    if (semanticRun >= PASSsemanticdone)
+        return;
+    if (_scope)
+    {
+        sc = _scope;
+        _scope = NULL;
+    }
+
+    parent = sc->parent;
+    Dsymbol *p = parent->pastMixin();
+    if (!p->isAggregateDeclaration())
+    {
+        ::error(loc, "deallocator can only be a member of aggregate, not %s %s",
+            p->kind(), p->toChars());
+        type = Type::terror;
+        errors = true;
+        return;
+    }
+    if (!type)
+        type = new TypeFunction(parameters, Type::tvoid, 0, LINKd, storage_class);
+
+    type = type->semantic(loc, sc);
+    assert(type->ty == Tfunction);
+
+    // Check that there is only one argument of type void*
+    TypeFunction *tf = (TypeFunction *)type;
+    if (Parameter::dim(tf->parameters) != 1)
+    {
+        error("one argument of type void* expected");
+    }
+    else
+    {
+        Parameter *fparam = Parameter::getNth(tf->parameters, 0);
+        if (!fparam->type->equals(Type::tvoid->pointerTo()))
+            error("one argument of type void* expected, not %s", fparam->type->toChars());
+    }
+
+    FuncDeclaration::semantic(sc);
+}
+
+const char *DeleteDeclaration::kind()
+{
+    return "deallocator";
+}
+
+bool DeleteDeclaration::isDelete()
+{
+    return true;
+}
+
+bool DeleteDeclaration::isVirtual()
+{
+    return false;
+}
+
+bool DeleteDeclaration::addPreInvariant()
+{
+    return false;
+}
+
+bool DeleteDeclaration::addPostInvariant()
+{
+    return false;
+}
diff --git a/gcc/d/dfrontend/globals.h b/gcc/d/dfrontend/globals.h
new file mode 100644
index 00000000000..248ba1e8175
--- /dev/null
+++ b/gcc/d/dfrontend/globals.h
@@ -0,0 +1,334 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/mars.h
+ */
+
+#ifndef DMD_GLOBALS_H
+#define DMD_GLOBALS_H
+
+#ifdef __DMC__
+#pragma once
+#endif
+
+#include "ctfloat.h"
+#include "outbuffer.h"
+#include "filename.h"
+
+// Can't include arraytypes.h here, need to declare these directly.
+template <typename TYPE> struct Array;
+
+// The state of array bounds checking
+enum BOUNDSCHECK
+{
+    BOUNDSCHECKdefault, // initial value
+    BOUNDSCHECKoff,     // never do bounds checking
+    BOUNDSCHECKon,      // always do bounds checking
+    BOUNDSCHECKsafeonly // do bounds checking only in @safe functions
+};
+
+enum CPU
+{
+    x87,
+    mmx,
+    sse,
+    sse2,
+    sse3,
+    ssse3,
+    sse4_1,
+    sse4_2,
+    avx,                // AVX1 instruction set
+    avx2,               // AVX2 instruction set
+    avx512,             // AVX-512 instruction set
+
+    // Special values that don't survive past the command line processing
+    baseline,           // (default) the minimum capability CPU
+    native              // the machine the compiler is being run on
+};
+
+// Put command line switches in here
+struct Param
+{
+    bool obj;           // write object file
+    bool link;          // perform link
+    bool dll;           // generate shared dynamic library
+    bool lib;           // write library file instead of object file(s)
+    bool multiobj;      // break one object file into multiple ones
+    bool oneobj;        // write one object file instead of multiple ones
+    bool trace;         // insert profiling hooks
+    bool tracegc;       // instrument calls to 'new'
+    bool verbose;       // verbose compile
+    bool vcg_ast;       // write-out codegen-ast
+    bool showColumns;   // print character (column) numbers in diagnostics
+    bool vtls;          // identify thread local variables
+    char vgc;           // identify gc usage
+    bool vfield;        // identify non-mutable field variables
+    bool vcomplex;      // identify complex/imaginary type usage
+    char symdebug;      // insert debug symbolic information
+    bool symdebugref;   // insert debug information for all referenced types, too
+    bool alwaysframe;   // always emit standard stack frame
+    bool optimize;      // run optimizer
+    bool map;           // generate linker .map file
+    bool is64bit;       // generate 64 bit code
+    bool isLP64;        // generate code for LP64
+    bool isLinux;       // generate code for linux
+    bool isOSX;         // generate code for Mac OSX
+    bool isWindows;     // generate code for Windows
+    bool isFreeBSD;     // generate code for FreeBSD
+    bool isOpenBSD;     // generate code for OpenBSD
+    bool isSolaris;     // generate code for Solaris
+    bool hasObjectiveC; // target supports Objective-C
+    bool mscoff;        // for Win32: write COFF object files instead of OMF
+    // 0: don't allow use of deprecated features
+    // 1: silently allow use of deprecated features
+    // 2: warn about the use of deprecated features
+    char useDeprecated;
+    bool useAssert;     // generate runtime code for assert()'s
+    bool useInvariants; // generate class invariant checks
+    bool useIn;         // generate precondition checks
+    bool useOut;        // generate postcondition checks
+    bool stackstomp;    // add stack stomping code
+    bool useSwitchError; // check for switches without a default
+    bool useUnitTests;  // generate unittest code
+    bool useInline;     // inline expand functions
+    bool useDIP25;      // implement http://wiki.dlang.org/DIP25
+    bool release;       // build release version
+    bool preservePaths; // true means don't strip path from source file
+    // 0: disable warnings
+    // 1: warnings as errors
+    // 2: informational warnings (no errors)
+    char warnings;
+    bool pic;           // generate position-independent-code for shared libs
+    bool color;         // use ANSI colors in console output
+    bool cov;           // generate code coverage data
+    unsigned char covPercent;   // 0..100 code coverage percentage required
+    bool nofloat;       // code should not pull in floating point support
+    bool ignoreUnsupportedPragmas;      // rather than error on them
+    bool enforcePropertySyntax;
+    bool betterC;       // be a "better C" compiler; no dependency on D runtime
+    bool addMain;       // add a default main() function
+    bool allInst;       // generate code for all template instantiations
+    bool check10378;    // check for issues transitioning to 10738
+    bool bug10378;      // use pre-bugzilla 10378 search strategy
+    bool vsafe;         // use enhanced @safe checking
+    bool showGaggedErrors;  // print gagged errors anyway
+
+    CPU cpu;                // CPU instruction set to target
+    BOUNDSCHECK useArrayBounds;
+
+    const char *argv0;    // program name
+    Array<const char *> *modFileAliasStrings; // array of char*'s of -I module filename alias strings
+    Array<const char *> *imppath;     // array of char*'s of where to look for import modules
+    Array<const char *> *fileImppath; // array of char*'s of where to look for file import modules
+    const char *objdir;   // .obj/.lib file output directory
+    const char *objname;  // .obj file output name
+    const char *libname;  // .lib file output name
+
+    bool doDocComments;  // process embedded documentation comments
+    const char *docdir;  // write documentation file to docdir directory
+    const char *docname; // write documentation file to docname
+    Array<const char *> *ddocfiles;  // macro include files for Ddoc
+
+    bool doHdrGeneration;  // process embedded documentation comments
+    const char *hdrdir;    // write 'header' file to docdir directory
+    const char *hdrname;   // write 'header' file to docname
+    bool hdrStripPlainFunctions; // strip the bodies of plain (non-template) functions
+
+    bool doJsonGeneration;    // write JSON file
+    const char *jsonfilename; // write JSON file to jsonfilename
+
+    unsigned debuglevel;   // debug level
+    Array<const char *> *debugids;     // debug identifiers
+
+    unsigned versionlevel; // version level
+    Array<const char *> *versionids;   // version identifiers
+
+    const char *defaultlibname; // default library for non-debug builds
+    const char *debuglibname;   // default library for debug builds
+    const char *mscrtlib;       // MS C runtime library
+
+    const char *moduleDepsFile; // filename for deps output
+    OutBuffer *moduleDeps;      // contents to be written to deps file
+
+    // Hidden debug switches
+    bool debugb;
+    bool debugc;
+    bool debugf;
+    bool debugr;
+    bool debugx;
+    bool debugy;
+
+    bool run;           // run resulting executable
+    Strings runargs;    // arguments for executable
+
+    // Linker stuff
+    Array<const char *> *objfiles;
+    Array<const char *> *linkswitches;
+    Array<const char *> *libfiles;
+    Array<const char *> *dllfiles;
+    const char *deffile;
+    const char *resfile;
+    const char *exefile;
+    const char *mapfile;
+};
+
+struct Compiler
+{
+    const char *vendor;     // Compiler backend name
+};
+
+typedef unsigned structalign_t;
+// magic value means "match whatever the underlying C compiler does"
+// other values are all powers of 2
+#define STRUCTALIGN_DEFAULT ((structalign_t) ~0)
+
+struct Global
+{
+    const char *inifilename;
+    const char *mars_ext;
+    const char *obj_ext;
+    const char *lib_ext;
+    const char *dll_ext;
+    const char *doc_ext;        // for Ddoc generated files
+    const char *ddoc_ext;       // for Ddoc macro include files
+    const char *hdr_ext;        // for D 'header' import files
+    const char *json_ext;       // for JSON files
+    const char *map_ext;        // for .map files
+    bool run_noext;             // allow -run sources without extensions.
+
+    const char *copyright;
+    const char *written;
+    const char *main_d;         // dummy filename for dummy main()
+    Array<const char *> *path;        // Array of char*'s which form the import lookup path
+    Array<const char *> *filePath;    // Array of char*'s which form the file import lookup path
+
+    const char *version;
+
+    Compiler compiler;
+    Param params;
+    unsigned errors;       // number of errors reported so far
+    unsigned warnings;     // number of warnings reported so far
+    FILE *stdmsg;          // where to send verbose messages
+    unsigned gag;          // !=0 means gag reporting of errors & warnings
+    unsigned gaggedErrors; // number of errors reported while gagged
+
+    unsigned errorLimit;
+
+    void* console;         // opaque pointer to console for controlling text attributes
+
+    /* Start gagging. Return the current number of gagged errors
+     */
+    unsigned startGagging();
+
+    /* End gagging, restoring the old gagged state.
+     * Return true if errors occurred while gagged.
+     */
+    bool endGagging(unsigned oldGagged);
+
+    /*  Increment the error count to record that an error
+     *  has occurred in the current context. An error message
+     *  may or may not have been printed.
+     */
+    void increaseErrorCount();
+
+    void _init();
+};
+
+extern Global global;
+
+// Because int64_t and friends may be any integral type of the
+// correct size, we have to explicitly ask for the correct
+// integer type to get the correct mangling with ddmd
+#if __LP64__
+// Be careful not to care about sign when using dinteger_t
+// use this instead of integer_t to
+// avoid conflicts with system #include's
+typedef unsigned long dinteger_t;
+// Signed and unsigned variants
+typedef long sinteger_t;
+typedef unsigned long uinteger_t;
+#else
+typedef unsigned long long dinteger_t;
+typedef long long sinteger_t;
+typedef unsigned long long uinteger_t;
+#endif
+
+typedef int8_t                  d_int8;
+typedef uint8_t                 d_uns8;
+typedef int16_t                 d_int16;
+typedef uint16_t                d_uns16;
+typedef int32_t                 d_int32;
+typedef uint32_t                d_uns32;
+typedef int64_t                 d_int64;
+typedef uint64_t                d_uns64;
+
+// Represents a D [ ] array
+template<typename T>
+struct DArray
+{
+    size_t length;
+    T *ptr;
+};
+
+// file location
+struct Loc
+{
+    const char *filename;
+    unsigned linnum;
+    unsigned charnum;
+
+    Loc()
+    {
+        linnum = 0;
+        charnum = 0;
+        filename = NULL;
+    }
+
+    Loc(const char *filename, unsigned linnum, unsigned charnum);
+
+    const char *toChars() const;
+    bool equals(const Loc& loc);
+};
+
+enum LINK
+{
+    LINKdefault,
+    LINKd,
+    LINKc,
+    LINKcpp,
+    LINKwindows,
+    LINKpascal,
+    LINKobjc,
+    LINKsystem,
+};
+
+enum CPPMANGLE
+{
+    CPPMANGLEdefault,
+    CPPMANGLEstruct,
+    CPPMANGLEclass,
+};
+
+enum MATCH
+{
+    MATCHnomatch,       // no match
+    MATCHconvert,       // match with conversions
+    MATCHconst,         // match with conversion to const
+    MATCHexact          // exact match
+};
+
+enum PINLINE
+{
+    PINLINEdefault,      // as specified on the command line
+    PINLINEnever,        // never inline
+    PINLINEalways        // always inline
+};
+
+typedef uinteger_t StorageClass;
+
+#endif /* DMD_GLOBALS_H */
diff --git a/gcc/d/dfrontend/hash.h b/gcc/d/dfrontend/hash.h
new file mode 100644
index 00000000000..97115a33f90
--- /dev/null
+++ b/gcc/d/dfrontend/hash.h
@@ -0,0 +1,75 @@
+/**
+ * Compiler implementation of the D programming language
+ * http://dlang.org
+ *
+ * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved
+ * Authors:   Martin Nowak, Walter Bright, http://www.digitalmars.com
+ * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:    $(DMDSRC root/_hash.h)
+ */
+
+#include <stdint.h>                     // uint{8|16|32}_t
+#include <stdlib.h>
+
+// MurmurHash2 was written by Austin Appleby, and is placed in the public
+// domain. The author hereby disclaims copyright to this source code.
+// https://sites.google.com/site/murmurhash/
+static inline uint32_t calcHash(const uint8_t *data, size_t len)
+{
+    // 'm' and 'r' are mixing constants generated offline.
+    // They're not really 'magic', they just happen to work well.
+
+    const uint32_t m = 0x5bd1e995;
+    const int r = 24;
+
+    // Initialize the hash to a 'random' value
+
+    uint32_t h = (uint32_t)len;
+
+    // Mix 4 bytes at a time into the hash
+
+    while(len >= 4)
+    {
+        uint32_t k = data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0];
+
+        k *= m;
+        k ^= k >> r;
+        k *= m;
+
+        h *= m;
+        h ^= k;
+
+        data += 4;
+        len -= 4;
+    }
+
+    // Handle the last few bytes of the input array
+
+    switch(len & 3)
+    {
+    case 3: h ^= data[2] << 16;
+    case 2: h ^= data[1] << 8;
+    case 1: h ^= data[0];
+        h *= m;
+    }
+
+    // Do a few final mixes of the hash to ensure the last few
+    // bytes are well-incorporated.
+
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+
+    return h;
+}
+
+static inline uint32_t calcHash(const char *data, size_t len)
+{
+    return calcHash((const uint8_t *)data, len);
+}
+
+// combine and mix two words (boost::hash_combine)
+static inline size_t mixHash(size_t h, size_t k)
+{
+    return h ^ (k + 0x9e3779b9 + (h << 6) + (h >> 2));
+}
diff --git a/gcc/d/dfrontend/hdrgen.c b/gcc/d/dfrontend/hdrgen.c
new file mode 100644
index 00000000000..8fb8df9cbe7
--- /dev/null
+++ b/gcc/d/dfrontend/hdrgen.c
@@ -0,0 +1,3461 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Dave Fladebo
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/hdrgen.c
+ */
+
+// Routines to emit header files
+
+#define TEST_EMIT_ALL  0        // For Testing
+
+#define LOG 0
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "rmem.h"
+
+#include "id.h"
+#include "init.h"
+
+#include "attrib.h"
+#include "cond.h"
+#include "doc.h"
+#include "enum.h"
+#include "import.h"
+#include "module.h"
+#include "mtype.h"
+#include "parse.h"
+#include "scope.h"
+#include "staticassert.h"
+#include "target.h"
+#include "template.h"
+#include "utf.h"
+#include "version.h"
+
+#include "declaration.h"
+#include "aggregate.h"
+#include "expression.h"
+#include "ctfe.h"
+#include "statement.h"
+#include "aliasthis.h"
+#include "nspace.h"
+#include "hdrgen.h"
+
+void linkageToBuffer(OutBuffer *buf, LINK linkage);
+void MODtoBuffer(OutBuffer *buf, MOD mod);
+
+void genhdrfile(Module *m)
+{
+    OutBuffer buf;
+    buf.doindent = 1;
+
+    buf.printf("// D import file generated from '%s'", m->srcfile->toChars());
+    buf.writenl();
+
+    HdrGenState hgs;
+    hgs.hdrgen = true;
+
+    toCBuffer(m, &buf, &hgs);
+
+    // Transfer image to file
+    m->hdrfile->setbuffer(buf.data, buf.offset);
+    buf.extractData();
+
+    ensurePathToNameExists(Loc(), m->hdrfile->toChars());
+    writeFile(m->loc, m->hdrfile);
+}
+
+class PrettyPrintVisitor : public Visitor
+{
+public:
+    OutBuffer *buf;
+    HdrGenState *hgs;
+    bool declstring; // set while declaring alias for string,wstring or dstring
+    EnumDeclaration *inEnumDecl;
+
+    PrettyPrintVisitor(OutBuffer *buf, HdrGenState *hgs)
+        : buf(buf), hgs(hgs), declstring(false), inEnumDecl(NULL)
+    {
+    }
+
+    void visit(Statement *s)
+    {
+        buf->printf("Statement::toCBuffer()");
+        buf->writenl();
+        assert(0);
+    }
+
+    void visit(ErrorStatement *s)
+    {
+        buf->printf("__error__");
+        buf->writenl();
+    }
+
+    void visit(ExpStatement *s)
+    {
+        if (s->exp && s->exp->op == TOKdeclaration)
+        {
+            // bypass visit(DeclarationExp)
+            ((DeclarationExp *)s->exp)->declaration->accept(this);
+            return;
+        }
+        if (s->exp)
+            s->exp->accept(this);
+        buf->writeByte(';');
+        if (!hgs->forStmtInit)
+            buf->writenl();
+    }
+
+    void visit(CompileStatement *s)
+    {
+        buf->writestring("mixin(");
+        s->exp->accept(this);
+        buf->writestring(");");
+        if (!hgs->forStmtInit)
+            buf->writenl();
+    }
+
+    void visit(CompoundStatement *s)
+    {
+        for (size_t i = 0; i < s->statements->dim; i++)
+        {
+            Statement *sx = (*s->statements)[i];
+            if (sx)
+                sx->accept(this);
+        }
+    }
+
+    void visit(CompoundDeclarationStatement *s)
+    {
+        bool anywritten = false;
+        for (size_t i = 0; i < s->statements->dim; i++)
+        {
+            Statement *sx = (*s->statements)[i];
+            ExpStatement *ds = sx ? sx->isExpStatement() : NULL;
+            if (ds && ds->exp->op == TOKdeclaration)
+            {
+                Dsymbol *d = ((DeclarationExp *)ds->exp)->declaration;
+                assert(d->isDeclaration());
+                if (VarDeclaration *v = d->isVarDeclaration())
+                    visitVarDecl(v, anywritten);
+                else
+                    d->accept(this);
+                anywritten = true;
+            }
+        }
+        buf->writeByte(';');
+        if (!hgs->forStmtInit)
+            buf->writenl();
+    }
+
+    void visit(UnrolledLoopStatement *s)
+    {
+        buf->writestring("unrolled {");
+        buf->writenl();
+        buf->level++;
+
+        for (size_t i = 0; i < s->statements->dim; i++)
+        {
+            Statement *sx = (*s->statements)[i];
+            if (sx)
+                sx->accept(this);
+        }
+
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+    }
+
+    void visit(ScopeStatement *s)
+    {
+        buf->writeByte('{');
+        buf->writenl();
+        buf->level++;
+
+        if (s->statement)
+            s->statement->accept(this);
+
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+    }
+
+    void visit(WhileStatement *s)
+    {
+        buf->writestring("while (");
+        s->condition->accept(this);
+        buf->writeByte(')');
+        buf->writenl();
+        if (s->_body)
+            s->_body->accept(this);
+    }
+
+    void visit(DoStatement *s)
+    {
+        buf->writestring("do");
+        buf->writenl();
+        if (s->_body)
+            s->_body->accept(this);
+        buf->writestring("while (");
+        s->condition->accept(this);
+        buf->writestring(");");
+        buf->writenl();
+    }
+
+    void visit(ForStatement *s)
+    {
+        buf->writestring("for (");
+        if (s->_init)
+        {
+            hgs->forStmtInit++;
+            s->_init->accept(this);
+            hgs->forStmtInit--;
+        }
+        else
+            buf->writeByte(';');
+        if (s->condition)
+        {
+            buf->writeByte(' ');
+            s->condition->accept(this);
+        }
+        buf->writeByte(';');
+        if (s->increment)
+        {
+            buf->writeByte(' ');
+            s->increment->accept(this);
+        }
+        buf->writeByte(')');
+        buf->writenl();
+        buf->writeByte('{');
+        buf->writenl();
+        buf->level++;
+        if (s->_body)
+            s->_body->accept(this);
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+    }
+
+    void visit(ForeachStatement *s)
+    {
+        buf->writestring(Token::toChars(s->op));
+        buf->writestring(" (");
+        for (size_t i = 0; i < s->parameters->dim; i++)
+        {
+            Parameter *p = (*s->parameters)[i];
+            if (i)
+                buf->writestring(", ");
+            if (stcToBuffer(buf, p->storageClass))
+                buf->writeByte(' ');
+            if (p->type)
+                typeToBuffer(p->type, p->ident);
+            else
+                buf->writestring(p->ident->toChars());
+        }
+        buf->writestring("; ");
+        s->aggr->accept(this);
+        buf->writeByte(')');
+        buf->writenl();
+        buf->writeByte('{');
+        buf->writenl();
+        buf->level++;
+        if (s->_body)
+            s->_body->accept(this);
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+    }
+
+    void visit(ForeachRangeStatement *s)
+    {
+        buf->writestring(Token::toChars(s->op));
+        buf->writestring(" (");
+
+        if (s->prm->type)
+            typeToBuffer(s->prm->type, s->prm->ident);
+        else
+            buf->writestring(s->prm->ident->toChars());
+
+        buf->writestring("; ");
+        s->lwr->accept(this);
+        buf->writestring(" .. ");
+        s->upr->accept(this);
+        buf->writeByte(')');
+        buf->writenl();
+        buf->writeByte('{');
+        buf->writenl();
+        buf->level++;
+        if (s->_body)
+            s->_body->accept(this);
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+    }
+
+    void visit(IfStatement *s)
+    {
+        buf->writestring("if (");
+        if (Parameter *p = s->prm)
+        {
+            StorageClass stc = p->storageClass;
+            if (!p->type && !stc)
+                stc = STCauto;
+            if (stcToBuffer(buf, stc))
+                buf->writeByte(' ');
+            if (p->type)
+                typeToBuffer(p->type, p->ident);
+            else
+                buf->writestring(p->ident->toChars());
+            buf->writestring(" = ");
+        }
+        s->condition->accept(this);
+        buf->writeByte(')');
+        buf->writenl();
+        if (!s->ifbody->isScopeStatement())
+            buf->level++;
+        s->ifbody->accept(this);
+        if (!s->ifbody->isScopeStatement())
+            buf->level--;
+        if (s->elsebody)
+        {
+            buf->writestring("else");
+            if (!s->elsebody->isIfStatement())
+            {
+                buf->writenl();
+            }
+            else
+            {
+                buf->writeByte(' ');
+            }
+            if (!s->elsebody->isScopeStatement() && !s->elsebody->isIfStatement())
+                buf->level++;
+            s->elsebody->accept(this);
+            if (!s->elsebody->isScopeStatement() && !s->elsebody->isIfStatement())
+                buf->level--;
+        }
+    }
+
+    void visit(ConditionalStatement *s)
+    {
+        s->condition->accept(this);
+        buf->writenl();
+        buf->writeByte('{');
+        buf->writenl();
+        buf->level++;
+        if (s->ifbody)
+            s->ifbody->accept(this);
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+        if (s->elsebody)
+        {
+            buf->writestring("else");
+            buf->writenl();
+            buf->writeByte('{');
+            buf->level++;
+            buf->writenl();
+            s->elsebody->accept(this);
+            buf->level--;
+            buf->writeByte('}');
+        }
+        buf->writenl();
+    }
+
+    void visit(PragmaStatement *s)
+    {
+        buf->writestring("pragma (");
+        buf->writestring(s->ident->toChars());
+        if (s->args && s->args->dim)
+        {
+            buf->writestring(", ");
+            argsToBuffer(s->args);
+        }
+        buf->writeByte(')');
+        if (s->_body)
+        {
+            buf->writenl();
+            buf->writeByte('{');
+            buf->writenl();
+            buf->level++;
+
+            s->_body->accept(this);
+
+            buf->level--;
+            buf->writeByte('}');
+            buf->writenl();
+        }
+        else
+        {
+            buf->writeByte(';');
+            buf->writenl();
+        }
+    }
+
+    void visit(StaticAssertStatement *s)
+    {
+        s->sa->accept(this);
+    }
+
+    void visit(SwitchStatement *s)
+    {
+        buf->writestring(s->isFinal ? "final switch (" : "switch (");
+        s->condition->accept(this);
+        buf->writeByte(')');
+        buf->writenl();
+        if (s->_body)
+        {
+            if (!s->_body->isScopeStatement())
+            {
+                buf->writeByte('{');
+                buf->writenl();
+                buf->level++;
+                s->_body->accept(this);
+                buf->level--;
+                buf->writeByte('}');
+                buf->writenl();
+            }
+            else
+            {
+                s->_body->accept(this);
+            }
+        }
+    }
+
+    void visit(CaseStatement *s)
+    {
+        buf->writestring("case ");
+        s->exp->accept(this);
+        buf->writeByte(':');
+        buf->writenl();
+        s->statement->accept(this);
+    }
+
+    void visit(CaseRangeStatement *s)
+    {
+        buf->writestring("case ");
+        s->first->accept(this);
+        buf->writestring(": .. case ");
+        s->last->accept(this);
+        buf->writeByte(':');
+        buf->writenl();
+        s->statement->accept(this);
+    }
+
+    void visit(DefaultStatement *s)
+    {
+        buf->writestring("default:");
+        buf->writenl();
+        s->statement->accept(this);
+    }
+
+    void visit(GotoDefaultStatement *s)
+    {
+        buf->writestring("goto default;");
+        buf->writenl();
+    }
+
+    void visit(GotoCaseStatement *s)
+    {
+        buf->writestring("goto case");
+        if (s->exp)
+        {
+            buf->writeByte(' ');
+            s->exp->accept(this);
+        }
+        buf->writeByte(';');
+        buf->writenl();
+    }
+
+    void visit(SwitchErrorStatement *s)
+    {
+        buf->writestring("SwitchErrorStatement::toCBuffer()");
+        buf->writenl();
+    }
+
+    void visit(ReturnStatement *s)
+    {
+        buf->printf("return ");
+        if (s->exp)
+            s->exp->accept(this);
+        buf->writeByte(';');
+        buf->writenl();
+    }
+
+    void visit(BreakStatement *s)
+    {
+        buf->writestring("break");
+        if (s->ident)
+        {
+            buf->writeByte(' ');
+            buf->writestring(s->ident->toChars());
+        }
+        buf->writeByte(';');
+        buf->writenl();
+    }
+
+    void visit(ContinueStatement *s)
+    {
+        buf->writestring("continue");
+        if (s->ident)
+        {
+            buf->writeByte(' ');
+            buf->writestring(s->ident->toChars());
+        }
+        buf->writeByte(';');
+        buf->writenl();
+    }
+
+    void visit(SynchronizedStatement *s)
+    {
+        buf->writestring("synchronized");
+        if (s->exp)
+        {
+            buf->writeByte('(');
+            s->exp->accept(this);
+            buf->writeByte(')');
+        }
+        if (s->_body)
+        {
+            buf->writeByte(' ');
+            s->_body->accept(this);
+        }
+    }
+
+    void visit(WithStatement *s)
+    {
+        buf->writestring("with (");
+        s->exp->accept(this);
+        buf->writestring(")");
+        buf->writenl();
+        if (s->_body)
+            s->_body->accept(this);
+    }
+
+    void visit(TryCatchStatement *s)
+    {
+        buf->writestring("try");
+        buf->writenl();
+        if (s->_body)
+            s->_body->accept(this);
+        for (size_t i = 0; i < s->catches->dim; i++)
+        {
+            Catch *c = (*s->catches)[i];
+            visit(c);
+        }
+    }
+
+    void visit(TryFinallyStatement *s)
+    {
+        buf->writestring("try");
+        buf->writenl();
+        buf->writeByte('{');
+        buf->writenl();
+        buf->level++;
+        s->_body->accept(this);
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+        buf->writestring("finally");
+        buf->writenl();
+        buf->writeByte('{');
+        buf->writenl();
+        buf->level++;
+        s->finalbody->accept(this);
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+    }
+
+    void visit(OnScopeStatement *s)
+    {
+        buf->writestring(Token::toChars(s->tok));
+        buf->writeByte(' ');
+        s->statement->accept(this);
+    }
+
+    void visit(ThrowStatement *s)
+    {
+        buf->printf("throw ");
+        s->exp->accept(this);
+        buf->writeByte(';');
+        buf->writenl();
+    }
+
+    void visit(DebugStatement *s)
+    {
+        if (s->statement)
+        {
+            s->statement->accept(this);
+        }
+    }
+
+    void visit(GotoStatement *s)
+    {
+        buf->writestring("goto ");
+        buf->writestring(s->ident->toChars());
+        buf->writeByte(';');
+        buf->writenl();
+    }
+
+    void visit(LabelStatement *s)
+    {
+        buf->writestring(s->ident->toChars());
+        buf->writeByte(':');
+        buf->writenl();
+        if (s->statement)
+            s->statement->accept(this);
+    }
+
+    void visit(AsmStatement *s)
+    {
+        buf->writestring("asm { ");
+        Token *t = s->tokens;
+        buf->level++;
+        while (t)
+        {
+            buf->writestring(t->toChars());
+            if (t->next &&
+                t->value != TOKmin      &&
+                t->value != TOKcomma    && t->next->value != TOKcomma    &&
+                t->value != TOKlbracket && t->next->value != TOKlbracket &&
+                                           t->next->value != TOKrbracket &&
+                t->value != TOKlparen   && t->next->value != TOKlparen   &&
+                                           t->next->value != TOKrparen   &&
+                t->value != TOKdot      && t->next->value != TOKdot)
+            {
+                buf->writeByte(' ');
+            }
+            t = t->next;
+        }
+        buf->level--;
+        buf->writestring("; }");
+        buf->writenl();
+    }
+
+#ifdef IN_GCC
+    void visit(ExtAsmStatement *s)
+    {
+        buf->writestring ("gcc asm { ");
+
+        if (s->insn)
+            buf->writestring (s->insn->toChars());
+
+        buf->writestring (" : ");
+
+        if (s->args)
+        {
+            for (size_t i = 0; i < s->args->dim; i++)
+            {
+                Identifier *name = (*s->names)[i];
+                Expression *constr = (*s->constraints)[i];
+                Expression *arg = (*s->args)[i];
+
+                if (name)
+                {
+                    buf->writestring ("[");
+                    buf->writestring (name->toChars());
+                    buf->writestring ("] ");
+                }
+
+                if (constr)
+                {
+                    buf->writestring (constr->toChars());
+                    buf->writestring (" ");
+                }
+
+                if (arg)
+                    buf->writestring (arg->toChars());
+
+                if (i < s->outputargs - 1)
+                    buf->writestring (", ");
+                else if (i == s->outputargs - 1)
+                    buf->writestring (" : ");
+                else if (i < s->args->dim - 1)
+                    buf->writestring (", ");
+            }
+        }
+
+        if (s->clobbers)
+        {
+            buf->writestring (" : ");
+            for (size_t i = 0; i < s->clobbers->dim; i++)
+            {
+                Expression *clobber = (*s->clobbers)[i];
+                buf->writestring (clobber->toChars());
+                if (i < s->clobbers->dim - 1)
+                    buf->writestring (", ");
+            }
+        }
+
+        buf->writestring ("; }");
+        buf->writenl();
+    }
+#endif
+
+    void visit(ImportStatement *s)
+    {
+        for (size_t i = 0; i < s->imports->dim; i++)
+        {
+            Dsymbol *imp = (*s->imports)[i];
+            imp->accept(this);
+        }
+    }
+
+    void visit(Catch *c)
+    {
+        buf->writestring("catch");
+        if (c->type)
+        {
+            buf->writeByte('(');
+            typeToBuffer(c->type, c->ident);
+            buf->writeByte(')');
+        }
+        buf->writenl();
+        buf->writeByte('{');
+        buf->writenl();
+        buf->level++;
+        if (c->handler)
+            c->handler->accept(this);
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    /**************************************************
+     * An entry point to pretty-print type.
+     */
+    void typeToBuffer(Type *t, Identifier *ident)
+    {
+        if (t->ty == Tfunction)
+        {
+            visitFuncIdentWithPrefix((TypeFunction *)t, ident, NULL, true);
+            return;
+        }
+
+        visitWithMask(t, 0);
+
+        if (ident)
+        {
+            buf->writeByte(' ');
+            buf->writestring(ident->toChars());
+        }
+    }
+
+    void visitWithMask(Type *t, unsigned char modMask)
+    {
+        // Tuples and functions don't use the type constructor syntax
+        if (modMask == t->mod ||
+            t->ty == Tfunction ||
+            t->ty == Ttuple)
+        {
+            t->accept(this);
+        }
+        else
+        {
+            unsigned char m = t->mod & ~(t->mod & modMask);
+            if (m & MODshared)
+            {
+                MODtoBuffer(buf, MODshared);
+                buf->writeByte('(');
+            }
+            if (m & MODwild)
+            {
+                MODtoBuffer(buf, MODwild);
+                buf->writeByte('(');
+            }
+            if (m & (MODconst | MODimmutable))
+            {
+                MODtoBuffer(buf, m & (MODconst | MODimmutable));
+                buf->writeByte('(');
+            }
+
+            t->accept(this);
+
+            if (m & (MODconst | MODimmutable))
+                buf->writeByte(')');
+            if (m & MODwild)
+                buf->writeByte(')');
+            if (m & MODshared)
+                buf->writeByte(')');
+        }
+    }
+
+    void visit(Type *t)
+    {
+        printf("t = %p, ty = %d\n", t, t->ty);
+        assert(0);
+    }
+
+    void visit(TypeError *t)
+    {
+        buf->writestring("_error_");
+    }
+
+    void visit(TypeBasic *t)
+    {
+        //printf("TypeBasic::toCBuffer2(t->mod = %d)\n", t->mod);
+        buf->writestring(t->dstring);
+    }
+
+    void visit(TypeVector *t)
+    {
+        //printf("TypeVector::toCBuffer2(t->mod = %d)\n", t->mod);
+        buf->writestring("__vector(");
+        visitWithMask(t->basetype, t->mod);
+        buf->writestring(")");
+    }
+
+    void visit(TypeSArray *t)
+    {
+        visitWithMask(t->next, t->mod);
+        buf->writeByte('[');
+        sizeToBuffer(t->dim);
+        buf->writeByte(']');
+    }
+
+    void visit(TypeDArray *t)
+    {
+        Type *ut = t->castMod(0);
+        if (declstring)
+            goto L1;
+        if (ut->equals(Type::tstring))
+            buf->writestring("string");
+        else if (ut->equals(Type::twstring))
+            buf->writestring("wstring");
+        else if (ut->equals(Type::tdstring))
+            buf->writestring("dstring");
+        else
+        {
+        L1:
+            visitWithMask(t->next, t->mod);
+            buf->writestring("[]");
+        }
+    }
+
+    void visit(TypeAArray *t)
+    {
+        visitWithMask(t->next, t->mod);
+        buf->writeByte('[');
+        visitWithMask(t->index, 0);
+        buf->writeByte(']');
+    }
+
+    void visit(TypePointer *t)
+    {
+        //printf("TypePointer::toCBuffer2() next = %d\n", t->next->ty);
+        if (t->next->ty == Tfunction)
+            visitFuncIdentWithPostfix((TypeFunction *)t->next, "function");
+        else
+        {
+            visitWithMask(t->next, t->mod);
+            buf->writeByte('*');
+        }
+    }
+
+    void visit(TypeReference *t)
+    {
+        visitWithMask(t->next, t->mod);
+        buf->writeByte('&');
+    }
+
+    void visit(TypeFunction *t)
+    {
+        //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t->isref);
+        visitFuncIdentWithPostfix(t, NULL);
+    }
+
+    // callback for TypeFunction::attributesApply
+    struct PrePostAppendStrings
+    {
+        OutBuffer *buf;
+        bool isPostfixStyle;
+        bool isCtor;
+
+        static int fp(void *param, const char *str)
+        {
+            PrePostAppendStrings *p = (PrePostAppendStrings *)param;
+
+            // don't write 'ref' for ctors
+            if (p->isCtor && strcmp(str, "ref") == 0)
+                return 0;
+
+            if ( p->isPostfixStyle) p->buf->writeByte(' ');
+            p->buf->writestring(str);
+            if (!p->isPostfixStyle) p->buf->writeByte(' ');
+            return 0;
+        }
+    };
+
+    void visitFuncIdentWithPostfix(TypeFunction *t, const char *ident)
+    {
+        if (t->inuse)
+        {
+            t->inuse = 2;              // flag error to caller
+            return;
+        }
+        t->inuse++;
+
+        PrePostAppendStrings pas;
+        pas.buf = buf;
+        pas.isCtor = false;
+        pas.isPostfixStyle = true;
+
+        if (t->linkage > LINKd && hgs->ddoc != 1 && !hgs->hdrgen)
+        {
+            linkageToBuffer(buf, t->linkage);
+            buf->writeByte(' ');
+        }
+
+        if (t->next)
+        {
+            typeToBuffer(t->next, NULL);
+            if (ident)
+                buf->writeByte(' ');
+        }
+        else if (hgs->ddoc)
+            buf->writestring("auto ");
+
+        if (ident)
+            buf->writestring(ident);
+
+        parametersToBuffer(t->parameters, t->varargs);
+
+        /* Use postfix style for attributes
+         */
+        if (t->mod)
+        {
+            buf->writeByte(' ');
+            MODtoBuffer(buf, t->mod);
+        }
+        t->attributesApply(&pas, &PrePostAppendStrings::fp);
+
+        t->inuse--;
+    }
+    void visitFuncIdentWithPrefix(TypeFunction *t, Identifier *ident, TemplateDeclaration *td, bool isPostfixStyle)
+    {
+        if (t->inuse)
+        {
+            t->inuse = 2;              // flag error to caller
+            return;
+        }
+        t->inuse++;
+
+        PrePostAppendStrings pas;
+        pas.buf = buf;
+        pas.isCtor = (ident == Id::ctor);
+        pas.isPostfixStyle = false;
+
+        /* Use 'storage class' (prefix) style for attributes
+         */
+        if (t->mod)
+        {
+            MODtoBuffer(buf, t->mod);
+            buf->writeByte(' ');
+        }
+        t->attributesApply(&pas, &PrePostAppendStrings::fp);
+
+        if (t->linkage > LINKd && hgs->ddoc != 1 && !hgs->hdrgen)
+        {
+            linkageToBuffer(buf, t->linkage);
+            buf->writeByte(' ');
+        }
+
+        if (ident && ident->toHChars2() != ident->toChars())
+        {
+            // Don't print return type for ctor, dtor, unittest, etc
+        }
+        else if (t->next)
+        {
+            typeToBuffer(t->next, NULL);
+            if (ident)
+                buf->writeByte(' ');
+        }
+        else if (hgs->ddoc)
+            buf->writestring("auto ");
+
+        if (ident)
+            buf->writestring(ident->toHChars2());
+
+        if (td)
+        {
+            buf->writeByte('(');
+            for (size_t i = 0; i < td->origParameters->dim; i++)
+            {
+                TemplateParameter *p = (*td->origParameters)[i];
+                if (i)
+                    buf->writestring(", ");
+                p->accept(this);
+            }
+            buf->writeByte(')');
+        }
+        parametersToBuffer(t->parameters, t->varargs);
+
+        t->inuse--;
+    }
+
+    void visit(TypeDelegate *t)
+    {
+        visitFuncIdentWithPostfix((TypeFunction *)t->next, "delegate");
+    }
+
+    void visitTypeQualifiedHelper(TypeQualified *t)
+    {
+        for (size_t i = 0; i < t->idents.dim; i++)
+        {
+            RootObject *id = t->idents[i];
+
+            if (id->dyncast() == DYNCAST_DSYMBOL)
+            {
+                buf->writeByte('.');
+                TemplateInstance *ti = (TemplateInstance *)id;
+                ti->accept(this);
+            }
+            else if (id->dyncast() == DYNCAST_EXPRESSION)
+            {
+                buf->writeByte('[');
+                ((Expression *)id)->accept(this);
+                buf->writeByte(']');
+            }
+            else if (id->dyncast() == DYNCAST_TYPE)
+            {
+                buf->writeByte('[');
+                ((Type *)id)->accept(this);
+                buf->writeByte(']');
+            }
+            else
+            {
+                buf->writeByte('.');
+                buf->writestring(id->toChars());
+            }
+        }
+    }
+
+    void visit(TypeIdentifier *t)
+    {
+        buf->writestring(t->ident->toChars());
+        visitTypeQualifiedHelper(t);
+    }
+
+    void visit(TypeInstance *t)
+    {
+        t->tempinst->accept(this);
+        visitTypeQualifiedHelper(t);
+    }
+
+    void visit(TypeTypeof *t)
+    {
+        buf->writestring("typeof(");
+        t->exp->accept(this);
+        buf->writeByte(')');
+        visitTypeQualifiedHelper(t);
+    }
+
+    void visit(TypeReturn *t)
+    {
+        buf->writestring("typeof(return)");
+        visitTypeQualifiedHelper(t);
+    }
+
+    void visit(TypeEnum *t)
+    {
+        buf->writestring(t->sym->toChars());
+    }
+
+    void visit(TypeStruct *t)
+    {
+        // Bugzilla 13776: Don't use ti->toAlias() to avoid forward reference error
+        // while printing messages.
+        TemplateInstance *ti = t->sym->parent ? t->sym->parent->isTemplateInstance() : NULL;
+        if (ti && ti->aliasdecl == t->sym)
+            buf->writestring(hgs->fullQual ? ti->toPrettyChars() : ti->toChars());
+        else
+            buf->writestring(hgs->fullQual ? t->sym->toPrettyChars() : t->sym->toChars());
+    }
+
+    void visit(TypeClass *t)
+    {
+        // Bugzilla 13776: Don't use ti->toAlias() to avoid forward reference error
+        // while printing messages.
+        TemplateInstance *ti = t->sym->parent->isTemplateInstance();
+        if (ti && ti->aliasdecl == t->sym)
+            buf->writestring(hgs->fullQual ? ti->toPrettyChars() : ti->toChars());
+        else
+            buf->writestring(hgs->fullQual ? t->sym->toPrettyChars() : t->sym->toChars());
+    }
+
+    void visit(TypeTuple *t)
+    {
+        parametersToBuffer(t->arguments, 0);
+    }
+
+    void visit(TypeSlice *t)
+    {
+        visitWithMask(t->next, t->mod);
+
+        buf->writeByte('[');
+        sizeToBuffer(t->lwr);
+        buf->writestring(" .. ");
+        sizeToBuffer(t->upr);
+        buf->writeByte(']');
+    }
+
+    void visit(TypeNull *t)
+    {
+        buf->writestring("typeof(null)");
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    void visit(Dsymbol *s)
+    {
+        buf->writestring(s->toChars());
+    }
+
+    void visit(StaticAssert *s)
+    {
+        buf->writestring(s->kind());
+        buf->writeByte('(');
+        s->exp->accept(this);
+        if (s->msg)
+        {
+            buf->writestring(", ");
+            s->msg->accept(this);
+        }
+        buf->writestring(");");
+        buf->writenl();
+    }
+
+    void visit(DebugSymbol *s)
+    {
+        buf->writestring("debug = ");
+        if (s->ident)
+            buf->writestring(s->ident->toChars());
+        else
+            buf->printf("%u", s->level);
+        buf->writestring(";");
+        buf->writenl();
+    }
+
+    void visit(VersionSymbol *s)
+    {
+        buf->writestring("version = ");
+        if (s->ident)
+            buf->writestring(s->ident->toChars());
+        else
+            buf->printf("%u", s->level);
+        buf->writestring(";");
+        buf->writenl();
+    }
+
+    void visit(EnumMember *em)
+    {
+        if (em->type)
+            typeToBuffer(em->type, em->ident);
+        else
+            buf->writestring(em->ident->toChars());
+        if (em->value())
+        {
+            buf->writestring(" = ");
+            em->value()->accept(this);
+        }
+    }
+
+    void visit(Import *imp)
+    {
+        if (hgs->hdrgen && imp->id == Id::object)
+            return;         // object is imported by default
+
+        if (imp->isstatic)
+            buf->writestring("static ");
+        buf->writestring("import ");
+        if (imp->aliasId)
+        {
+            buf->printf("%s = ", imp->aliasId->toChars());
+        }
+        if (imp->packages && imp->packages->dim)
+        {
+            for (size_t i = 0; i < imp->packages->dim; i++)
+            {
+                Identifier *pid = (*imp->packages)[i];
+                buf->printf("%s.", pid->toChars());
+            }
+        }
+        buf->printf("%s", imp->id->toChars());
+        if (imp->names.dim)
+        {
+            buf->writestring(" : ");
+            for (size_t i = 0; i < imp->names.dim; i++)
+            {
+                if (i)
+                    buf->writestring(", ");
+
+                Identifier *name = imp->names[i];
+                Identifier *alias = imp->aliases[i];
+                if (alias)
+                    buf->printf("%s = %s", alias->toChars(), name->toChars());
+                else
+                    buf->printf("%s", name->toChars());
+            }
+        }
+        buf->printf(";");
+        buf->writenl();
+    }
+
+    void visit(AliasThis *d)
+    {
+        buf->writestring("alias ");
+        buf->writestring(d->ident->toChars());
+        buf->writestring(" this;\n");
+    }
+
+    void visit(AttribDeclaration *d)
+    {
+        if (!d->decl)
+        {
+            buf->writeByte(';');
+            buf->writenl();
+            return;
+        }
+
+        if (d->decl->dim == 0)
+            buf->writestring("{}");
+        else if (hgs->hdrgen && d->decl->dim == 1 && (*d->decl)[0]->isUnitTestDeclaration())
+        {
+            // hack for bugzilla 8081
+            buf->writestring("{}");
+        }
+        else if (d->decl->dim == 1)
+        {
+            ((*d->decl)[0])->accept(this);
+            return;
+        }
+        else
+        {
+            buf->writenl();
+            buf->writeByte('{');
+            buf->writenl();
+            buf->level++;
+            for (size_t i = 0; i < d->decl->dim; i++)
+            {
+                Dsymbol *de = (*d->decl)[i];
+                de->accept(this);
+            }
+            buf->level--;
+            buf->writeByte('}');
+        }
+        buf->writenl();
+    }
+
+    void visit(StorageClassDeclaration *d)
+    {
+        if (stcToBuffer(buf, d->stc))
+            buf->writeByte(' ');
+        visit((AttribDeclaration *)d);
+    }
+
+    void visit(DeprecatedDeclaration *d)
+    {
+        buf->writestring("deprecated(");
+        d->msg->accept(this);
+        buf->writestring(") ");
+        visit((AttribDeclaration *)d);
+    }
+
+    void visit(LinkDeclaration *d)
+    {
+        const char *p;
+
+        switch (d->linkage)
+        {
+            case LINKd:             p = "D";                break;
+            case LINKc:             p = "C";                break;
+            case LINKcpp:           p = "C++";              break;
+            case LINKwindows:       p = "Windows";          break;
+            case LINKpascal:        p = "Pascal";           break;
+            case LINKobjc:          p = "Objective-C";      break;
+            default:
+                assert(0);
+                break;
+        }
+        buf->writestring("extern (");
+        buf->writestring(p);
+        buf->writestring(") ");
+        visit((AttribDeclaration *)d);
+    }
+
+    void visit(CPPMangleDeclaration *d)
+    {
+        const char *p;
+
+        switch (d->cppmangle)
+        {
+            case CPPMANGLEclass:    p = "class";            break;
+            case CPPMANGLEstruct:   p = "struct";           break;
+            default:
+                assert(0);
+                break;
+        }
+        buf->writestring("extern (C++, ");
+        buf->writestring(p);
+        buf->writestring(") ");
+        visit((AttribDeclaration *)d);
+    }
+
+    void visit(ProtDeclaration *d)
+    {
+        protectionToBuffer(buf, d->protection);
+        buf->writeByte(' ');
+        visit((AttribDeclaration *)d);
+    }
+
+    void visit(AlignDeclaration *d)
+    {
+        if (!d->ealign)
+            buf->printf("align ");
+        else
+            buf->printf("align (%s)", d->ealign->toChars());
+        visit((AttribDeclaration *)d);
+    }
+
+    void visit(AnonDeclaration *d)
+    {
+        buf->printf(d->isunion ? "union" : "struct");
+        buf->writenl();
+        buf->writestring("{");
+        buf->writenl();
+        buf->level++;
+        if (d->decl)
+        {
+            for (size_t i = 0; i < d->decl->dim; i++)
+            {
+                Dsymbol *de = (*d->decl)[i];
+                de->accept(this);
+            }
+        }
+        buf->level--;
+        buf->writestring("}");
+        buf->writenl();
+    }
+
+    void visit(PragmaDeclaration *d)
+    {
+        buf->printf("pragma (%s", d->ident->toChars());
+        if (d->args && d->args->dim)
+        {
+            buf->writestring(", ");
+            argsToBuffer(d->args);
+        }
+        buf->writeByte(')');
+        visit((AttribDeclaration *)d);
+    }
+
+    void visit(ConditionalDeclaration *d)
+    {
+        d->condition->accept(this);
+        if (d->decl || d->elsedecl)
+        {
+            buf->writenl();
+            buf->writeByte('{');
+            buf->writenl();
+            buf->level++;
+            if (d->decl)
+            {
+                for (size_t i = 0; i < d->decl->dim; i++)
+                {
+                    Dsymbol *de = (*d->decl)[i];
+                    de->accept(this);
+                }
+            }
+            buf->level--;
+            buf->writeByte('}');
+            if (d->elsedecl)
+            {
+                buf->writenl();
+                buf->writestring("else");
+                buf->writenl();
+                buf->writeByte('{');
+                buf->writenl();
+                buf->level++;
+                for (size_t i = 0; i < d->elsedecl->dim; i++)
+                {
+                    Dsymbol *de = (*d->elsedecl)[i];
+                    de->accept(this);
+                }
+                buf->level--;
+                buf->writeByte('}');
+            }
+        }
+        else
+            buf->writeByte(':');
+        buf->writenl();
+    }
+
+    void visit(CompileDeclaration *d)
+    {
+        buf->writestring("mixin(");
+        d->exp->accept(this);
+        buf->writestring(");");
+        buf->writenl();
+    }
+
+    void visit(UserAttributeDeclaration *d)
+    {
+        buf->writestring("@(");
+        argsToBuffer(d->atts);
+        buf->writeByte(')');
+        visit((AttribDeclaration *)d);
+    }
+
+    void visit(TemplateDeclaration *d)
+    {
+    #if 0 // Should handle template functions for doc generation
+        if (onemember && onemember->isFuncDeclaration())
+            buf->writestring("foo ");
+    #endif
+        if ((hgs->hdrgen || hgs->fullDump) && visitEponymousMember(d))
+            return;
+
+        if (hgs->ddoc)
+            buf->writestring(d->kind());
+        else
+            buf->writestring("template");
+        buf->writeByte(' ');
+        buf->writestring(d->ident->toChars());
+        buf->writeByte('(');
+        visitTemplateParameters(hgs->ddoc ? d->origParameters : d->parameters);
+        buf->writeByte(')');
+        visitTemplateConstraint(d->constraint);
+
+        if (hgs->hdrgen || hgs->fullDump)
+        {
+            hgs->tpltMember++;
+            buf->writenl();
+            buf->writeByte('{');
+            buf->writenl();
+            buf->level++;
+            for (size_t i = 0; i < d->members->dim; i++)
+            {
+                Dsymbol *s = (*d->members)[i];
+                s->accept(this);
+            }
+            buf->level--;
+            buf->writeByte('}');
+            buf->writenl();
+            hgs->tpltMember--;
+        }
+    }
+
+    bool visitEponymousMember(TemplateDeclaration *d)
+    {
+        if (!d->members || d->members->dim != 1)
+            return false;
+
+        Dsymbol *onemember = (*d->members)[0];
+        if (onemember->ident != d->ident)
+            return false;
+
+        if (FuncDeclaration *fd = onemember->isFuncDeclaration())
+        {
+            assert(fd->type);
+            if (stcToBuffer(buf, fd->storage_class))
+                buf->writeByte(' ');
+            functionToBufferFull((TypeFunction *)fd->type, buf, d->ident, hgs, d);
+            visitTemplateConstraint(d->constraint);
+
+            hgs->tpltMember++;
+            bodyToBuffer(fd);
+            hgs->tpltMember--;
+            return true;
+        }
+        if (AggregateDeclaration *ad = onemember->isAggregateDeclaration())
+        {
+            buf->writestring(ad->kind());
+            buf->writeByte(' ');
+            buf->writestring(ad->ident->toChars());
+            buf->writeByte('(');
+            visitTemplateParameters(hgs->ddoc ? d->origParameters : d->parameters);
+            buf->writeByte(')');
+            visitTemplateConstraint(d->constraint);
+            visitBaseClasses(ad->isClassDeclaration());
+
+            hgs->tpltMember++;
+            if (ad->members)
+            {
+                buf->writenl();
+                buf->writeByte('{');
+                buf->writenl();
+                buf->level++;
+                for (size_t i = 0; i < ad->members->dim; i++)
+                {
+                    Dsymbol *s = (*ad->members)[i];
+                    s->accept(this);
+                }
+                buf->level--;
+                buf->writeByte('}');
+            }
+            else
+                buf->writeByte(';');
+            buf->writenl();
+            hgs->tpltMember--;
+            return true;
+        }
+        if (VarDeclaration *vd = onemember->isVarDeclaration())
+        {
+            if (d->constraint)
+                return false;
+
+            if (stcToBuffer(buf, vd->storage_class))
+                buf->writeByte(' ');
+            if (vd->type)
+                typeToBuffer(vd->type, vd->ident);
+            else
+                buf->writestring(vd->ident->toChars());
+
+            buf->writeByte('(');
+            visitTemplateParameters(hgs->ddoc ? d->origParameters : d->parameters);
+            buf->writeByte(')');
+
+            if (vd->_init)
+            {
+                buf->writestring(" = ");
+                ExpInitializer *ie = vd->_init->isExpInitializer();
+                if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit))
+                    ((AssignExp *)ie->exp)->e2->accept(this);
+                else
+                    vd->_init->accept(this);
+            }
+            buf->writeByte(';');
+            buf->writenl();
+            return true;
+        }
+
+        return false;
+    }
+    void visitTemplateParameters(TemplateParameters *parameters)
+    {
+        if (!parameters || !parameters->dim)
+            return;
+        for (size_t i = 0; i < parameters->dim; i++)
+        {
+            TemplateParameter *p = (*parameters)[i];
+            if (i)
+                buf->writestring(", ");
+            p->accept(this);
+        }
+    }
+    void visitTemplateConstraint(Expression *constraint)
+    {
+        if (!constraint)
+            return;
+        buf->writestring(" if (");
+        constraint->accept(this);
+        buf->writeByte(')');
+    }
+
+    void visit(TemplateInstance *ti)
+    {
+        buf->writestring(ti->name->toChars());
+        tiargsToBuffer(ti);
+
+        if (hgs->fullDump)
+        {
+            buf->writenl();
+            if (ti->aliasdecl)
+            {
+                // the ti.aliasDecl is the instantiated body
+                // if we have it, print it.
+                ti->aliasdecl->accept(this);
+            }
+        }
+    }
+
+    void visit(TemplateMixin *tm)
+    {
+        buf->writestring("mixin ");
+
+        typeToBuffer(tm->tqual, NULL);
+        tiargsToBuffer(tm);
+
+        if (tm->ident && memcmp(tm->ident->toChars(), "__mixin", 7) != 0)
+        {
+            buf->writeByte(' ');
+            buf->writestring(tm->ident->toChars());
+        }
+        buf->writeByte(';');
+        buf->writenl();
+    }
+
+    void tiargsToBuffer(TemplateInstance *ti)
+    {
+        buf->writeByte('!');
+        if (ti->nest)
+        {
+            buf->writestring("(...)");
+            return;
+        }
+        if (!ti->tiargs)
+        {
+            buf->writestring("()");
+            return;
+        }
+
+        if (ti->tiargs->dim == 1)
+        {
+            RootObject *oarg = (*ti->tiargs)[0];
+            if (Type *t = isType(oarg))
+            {
+                if (t->equals(Type::tstring) ||
+                    t->equals(Type::twstring) ||
+                    t->equals(Type::tdstring) ||
+                    t->mod == 0 &&
+                    (t->isTypeBasic() ||
+                     t->ty == Tident && ((TypeIdentifier *)t)->idents.dim == 0))
+                {
+                    buf->writestring(t->toChars());
+                    return;
+                }
+            }
+            else if (Expression *e = isExpression(oarg))
+            {
+                if (e->op == TOKint64 ||
+                    e->op == TOKfloat64 ||
+                    e->op == TOKnull ||
+                    e->op == TOKstring ||
+                    e->op == TOKthis)
+                {
+                    buf->writestring(e->toChars());
+                    return;
+                }
+            }
+        }
+        buf->writeByte('(');
+        ti->nest++;
+        for (size_t i = 0; i < ti->tiargs->dim; i++)
+        {
+            RootObject *arg = (*ti->tiargs)[i];
+            if (i)
+                buf->writestring(", ");
+            objectToBuffer(arg);
+        }
+        ti->nest--;
+        buf->writeByte(')');
+    }
+
+    /****************************************
+     * This makes a 'pretty' version of the template arguments.
+     * It's analogous to genIdent() which makes a mangled version.
+     */
+    void objectToBuffer(RootObject *oarg)
+    {
+        //printf("objectToBuffer()\n");
+
+        /* The logic of this should match what genIdent() does. The _dynamic_cast()
+         * function relies on all the pretty strings to be unique for different classes
+         * (see Bugzilla 7375).
+         * Perhaps it would be better to demangle what genIdent() does.
+         */
+        if (Type *t = isType(oarg))
+        {
+            //printf("\tt: %s ty = %d\n", t->toChars(), t->ty);
+            typeToBuffer(t, NULL);
+        }
+        else if (Expression *e = isExpression(oarg))
+        {
+            if (e->op == TOKvar)
+                e = e->optimize(WANTvalue);         // added to fix Bugzilla 7375
+            e->accept(this);
+        }
+        else if (Dsymbol *s = isDsymbol(oarg))
+        {
+            const char *p = s->ident ? s->ident->toChars() : s->toChars();
+            buf->writestring(p);
+        }
+        else if (Tuple *v = isTuple(oarg))
+        {
+            Objects *args = &v->objects;
+            for (size_t i = 0; i < args->dim; i++)
+            {
+                RootObject *arg = (*args)[i];
+                if (i)
+                    buf->writestring(", ");
+                objectToBuffer(arg);
+            }
+        }
+        else if (!oarg)
+        {
+            buf->writestring("NULL");
+        }
+        else
+        {
+    #ifdef DEBUG
+            printf("bad Object = %p\n", oarg);
+    #endif
+            assert(0);
+        }
+    }
+
+    void visit(EnumDeclaration *d)
+    {
+        EnumDeclaration *oldInEnumDecl = inEnumDecl;
+        inEnumDecl = d;
+        buf->writestring("enum ");
+        if (d->ident)
+        {
+            buf->writestring(d->ident->toChars());
+            buf->writeByte(' ');
+        }
+        if (d->memtype)
+        {
+            buf->writestring(": ");
+            typeToBuffer(d->memtype, NULL);
+        }
+        if (!d->members)
+        {
+            buf->writeByte(';');
+            buf->writenl();
+            inEnumDecl = oldInEnumDecl;
+            return;
+        }
+        buf->writenl();
+        buf->writeByte('{');
+        buf->writenl();
+        buf->level++;
+        for (size_t i = 0; i < d->members->dim; i++)
+        {
+            EnumMember *em = (*d->members)[i]->isEnumMember();
+            if (!em)
+                continue;
+            em->accept(this);
+            buf->writeByte(',');
+            buf->writenl();
+        }
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+        inEnumDecl = oldInEnumDecl;
+    }
+
+    void visit(Nspace *d)
+    {
+        buf->writestring("extern (C++, ");
+        buf->writestring(d->ident->toChars());
+        buf->writeByte(')');
+        buf->writenl();
+        buf->writeByte('{');
+        buf->writenl();
+        buf->level++;
+        for (size_t i = 0; i < d->members->dim; i++)
+        {
+            Dsymbol *s = (*d->members)[i];
+            s->accept(this);
+        }
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+    }
+
+    void visit(StructDeclaration *d)
+    {
+        buf->printf("%s ", d->kind());
+        if (!d->isAnonymous())
+            buf->writestring(d->toChars());
+        if (!d->members)
+        {
+            buf->writeByte(';');
+            buf->writenl();
+            return;
+        }
+        buf->writenl();
+        buf->writeByte('{');
+        buf->writenl();
+        buf->level++;
+        for (size_t i = 0; i < d->members->dim; i++)
+        {
+            Dsymbol *s = (*d->members)[i];
+            s->accept(this);
+        }
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+    }
+
+    void visit(ClassDeclaration *d)
+    {
+        if (!d->isAnonymous())
+        {
+            buf->writestring(d->kind());
+            buf->writeByte(' ');
+            buf->writestring(d->ident->toChars());
+        }
+        visitBaseClasses(d);
+        if (d->members)
+        {
+            buf->writenl();
+            buf->writeByte('{');
+            buf->writenl();
+            buf->level++;
+            for (size_t i = 0; i < d->members->dim; i++)
+            {
+                Dsymbol *s = (*d->members)[i];
+                s->accept(this);
+            }
+            buf->level--;
+            buf->writeByte('}');
+        }
+        else
+            buf->writeByte(';');
+        buf->writenl();
+    }
+
+    void visitBaseClasses(ClassDeclaration *d)
+    {
+        if (!d || !d->baseclasses->dim)
+            return;
+
+        buf->writestring(" : ");
+        for (size_t i = 0; i < d->baseclasses->dim; i++)
+        {
+            if (i)
+                buf->writestring(", ");
+            BaseClass *b = (*d->baseclasses)[i];
+            typeToBuffer(b->type, NULL);
+        }
+    }
+
+    void visit(AliasDeclaration *d)
+    {
+        buf->writestring("alias ");
+        if (d->aliassym)
+        {
+            buf->writestring(d->ident->toChars());
+            buf->writestring(" = ");
+            if (stcToBuffer(buf, d->storage_class))
+                buf->writeByte(' ');
+            d->aliassym->accept(this);
+        }
+        else if (d->type->ty == Tfunction)
+        {
+            if (stcToBuffer(buf, d->storage_class))
+                buf->writeByte(' ');
+            typeToBuffer(d->type, d->ident);
+        }
+        else
+        {
+            declstring = (d->ident == Id::string || d->ident == Id::wstring || d->ident == Id::dstring);
+            buf->writestring(d->ident->toChars());
+            buf->writestring(" = ");
+            if (stcToBuffer(buf, d->storage_class))
+                buf->writeByte(' ');
+            typeToBuffer(d->type, NULL);
+            declstring = false;
+        }
+        buf->writeByte(';');
+        buf->writenl();
+    }
+
+    void visit(VarDeclaration *d)
+    {
+        visitVarDecl(d, false);
+        buf->writeByte(';');
+        buf->writenl();
+    }
+    void visitVarDecl(VarDeclaration *v, bool anywritten)
+    {
+        if (anywritten)
+        {
+            buf->writestring(", ");
+            buf->writestring(v->ident->toChars());
+        }
+        else
+        {
+            if (stcToBuffer(buf, v->storage_class))
+                buf->writeByte(' ');
+            if (v->type)
+                typeToBuffer(v->type, v->ident);
+            else
+                buf->writestring(v->ident->toChars());
+        }
+        if (v->_init)
+        {
+            buf->writestring(" = ");
+            ExpInitializer *ie = v->_init->isExpInitializer();
+            if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit))
+                ((AssignExp *)ie->exp)->e2->accept(this);
+            else
+                v->_init->accept(this);
+        }
+    }
+
+    void visit(FuncDeclaration *f)
+    {
+        //printf("FuncDeclaration::toCBuffer() '%s'\n", f->toChars());
+
+        if (stcToBuffer(buf, f->storage_class))
+            buf->writeByte(' ');
+        TypeFunction *tf = (TypeFunction *)f->type;
+        typeToBuffer(tf, f->ident);
+        if (hgs->hdrgen)
+        {
+            // if the return type is missing (e.g. ref functions or auto)
+            if (!tf->next || f->storage_class & STCauto)
+            {
+                hgs->autoMember++;
+                bodyToBuffer(f);
+                hgs->autoMember--;
+            }
+            else if (hgs->tpltMember == 0 && global.params.hdrStripPlainFunctions)
+            {
+                buf->writeByte(';');
+                buf->writenl();
+            }
+            else
+                bodyToBuffer(f);
+        }
+        else
+            bodyToBuffer(f);
+    }
+
+    void bodyToBuffer(FuncDeclaration *f)
+    {
+        if (!f->fbody || (hgs->hdrgen && global.params.hdrStripPlainFunctions && !hgs->autoMember && !hgs->tpltMember))
+        {
+            buf->writeByte(';');
+            buf->writenl();
+            return;
+        }
+
+        int savetlpt = hgs->tpltMember;
+        int saveauto = hgs->autoMember;
+        hgs->tpltMember = 0;
+        hgs->autoMember = 0;
+
+        buf->writenl();
+
+        // in{}
+        if (f->frequire)
+        {
+            buf->writestring("in");
+            buf->writenl();
+            f->frequire->accept(this);
+        }
+
+        // out{}
+        if (f->fensure)
+        {
+            buf->writestring("out");
+            if (f->outId)
+            {
+                buf->writeByte('(');
+                buf->writestring(f->outId->toChars());
+                buf->writeByte(')');
+            }
+            buf->writenl();
+            f->fensure->accept(this);
+        }
+
+        if (f->frequire || f->fensure)
+        {
+            buf->writestring("body");
+            buf->writenl();
+        }
+
+        buf->writeByte('{');
+        buf->writenl();
+        buf->level++;
+        f->fbody->accept(this);
+        buf->level--;
+        buf->writeByte('}');
+        buf->writenl();
+
+        hgs->tpltMember = savetlpt;
+        hgs->autoMember = saveauto;
+    }
+
+    void visit(FuncLiteralDeclaration *f)
+    {
+        if (f->type->ty == Terror)
+        {
+            buf->writestring("__error");
+            return;
+        }
+
+        if (f->tok != TOKreserved)
+        {
+            buf->writestring(f->kind());
+            buf->writeByte(' ');
+        }
+
+        TypeFunction *tf = (TypeFunction *)f->type;
+        // Don't print tf->mod, tf->trust, and tf->linkage
+        if (!f->inferRetType && tf->next)
+            typeToBuffer(tf->next, NULL);
+        parametersToBuffer(tf->parameters, tf->varargs);
+
+        CompoundStatement *cs = f->fbody->isCompoundStatement();
+        Statement *s1;
+        if (f->semanticRun >= PASSsemantic3done && cs)
+        {
+            s1 = (*cs->statements)[cs->statements->dim - 1];
+        }
+        else
+            s1 = !cs ? f->fbody : NULL;
+        ReturnStatement *rs = s1 ? s1->isReturnStatement() : NULL;
+        if (rs && rs->exp)
+        {
+            buf->writestring(" => ");
+            rs->exp->accept(this);
+        }
+        else
+        {
+            hgs->tpltMember++;
+            bodyToBuffer(f);
+            hgs->tpltMember--;
+        }
+    }
+
+    void visit(PostBlitDeclaration *d)
+    {
+        if (stcToBuffer(buf, d->storage_class))
+             buf->writeByte(' ');
+        buf->writestring("this(this)");
+        bodyToBuffer(d);
+    }
+
+    void visit(DtorDeclaration *d)
+    {
+        if (d->storage_class & STCtrusted)
+            buf->writestring("@trusted ");
+        if (d->storage_class & STCsafe)
+            buf->writestring("@safe ");
+        if (d->storage_class & STCnogc)
+            buf->writestring("@nogc ");
+        if (d->storage_class & STCdisable)
+            buf->writestring("@disable ");
+
+        buf->writestring("~this()");
+        bodyToBuffer(d);
+    }
+
+    void visit(StaticCtorDeclaration *d)
+    {
+        if (stcToBuffer(buf, d->storage_class & ~STCstatic))
+            buf->writeByte(' ');
+        if (d->isSharedStaticCtorDeclaration())
+            buf->writestring("shared ");
+        buf->writestring("static this()");
+        if (hgs->hdrgen && !hgs->tpltMember)
+        {
+            buf->writeByte(';');
+            buf->writenl();
+        }
+        else
+            bodyToBuffer(d);
+    }
+
+    void visit(StaticDtorDeclaration *d)
+    {
+        if (hgs->hdrgen)
+            return;
+        if (stcToBuffer(buf, d->storage_class & ~STCstatic))
+            buf->writeByte(' ');
+        if (d->isSharedStaticDtorDeclaration())
+            buf->writestring("shared ");
+        buf->writestring("static ~this()");
+        bodyToBuffer(d);
+    }
+
+    void visit(InvariantDeclaration *d)
+    {
+        if (hgs->hdrgen)
+            return;
+        if (stcToBuffer(buf, d->storage_class))
+            buf->writeByte(' ');
+        buf->writestring("invariant");
+        bodyToBuffer(d);
+    }
+
+    void visit(UnitTestDeclaration *d)
+    {
+        if (hgs->hdrgen)
+            return;
+        if (stcToBuffer(buf, d->storage_class))
+            buf->writeByte(' ');
+        buf->writestring("unittest");
+        bodyToBuffer(d);
+    }
+
+    void visit(NewDeclaration *d)
+    {
+        if (stcToBuffer(buf, d->storage_class & ~STCstatic))
+            buf->writeByte(' ');
+        buf->writestring("new");
+        parametersToBuffer(d->parameters, d->varargs);
+        bodyToBuffer(d);
+    }
+
+    void visit(DeleteDeclaration *d)
+    {
+        if (stcToBuffer(buf, d->storage_class & ~STCstatic))
+            buf->writeByte(' ');
+        buf->writestring("delete");
+        parametersToBuffer(d->parameters, 0);
+        bodyToBuffer(d);
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    void visit(ErrorInitializer *iz)
+    {
+        buf->writestring("__error__");
+    }
+
+    void visit(VoidInitializer *iz)
+    {
+        buf->writestring("void");
+    }
+
+    void visit(StructInitializer *si)
+    {
+        //printf("StructInitializer::toCBuffer()\n");
+        buf->writeByte('{');
+        for (size_t i = 0; i < si->field.dim; i++)
+        {
+            if (i)
+                buf->writestring(", ");
+            if (Identifier *id = si->field[i])
+            {
+                buf->writestring(id->toChars());
+                buf->writeByte(':');
+            }
+            if (Initializer *iz = si->value[i])
+                iz->accept(this);
+        }
+        buf->writeByte('}');
+    }
+
+    void visit(ArrayInitializer *ai)
+    {
+        buf->writeByte('[');
+        for (size_t i = 0; i < ai->index.dim; i++)
+        {
+            if (i)
+                buf->writestring(", ");
+            if (Expression *ex = ai->index[i])
+            {
+                ex->accept(this);
+                buf->writeByte(':');
+            }
+            if (Initializer *iz = ai->value[i])
+                iz->accept(this);
+        }
+        buf->writeByte(']');
+    }
+
+    void visit(ExpInitializer *ei)
+    {
+        ei->exp->accept(this);
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    /**************************************************
+     * Write out argument list to buf.
+     */
+    void argsToBuffer(Expressions *expressions, Expression *basis = NULL)
+    {
+        if (!expressions || !expressions->dim)
+            return;
+
+        for (size_t i = 0; i < expressions->dim; i++)
+        {
+            Expression *el = (*expressions)[i];
+            if (i)
+                buf->writestring(", ");
+            if (!el)
+                el = basis;
+            if (el)
+                expToBuffer(el, PREC_assign);
+        }
+    }
+
+    void sizeToBuffer(Expression *e)
+    {
+        if (e->type == Type::tsize_t)
+        {
+            Expression *ex = (e->op == TOKcast ? ((CastExp *)e)->e1 : e);
+            ex = ex->optimize(WANTvalue);
+
+            dinteger_t uval = ex->op == TOKint64 ? ex->toInteger() : (dinteger_t)-1;
+            if ((sinteger_t)uval >= 0)
+            {
+                dinteger_t sizemax;
+                if (Target::ptrsize == 4)
+                    sizemax = 0xFFFFFFFFUL;
+                else if (Target::ptrsize == 8)
+                    sizemax = 0xFFFFFFFFFFFFFFFFULL;
+                else
+                    assert(0);
+                if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFULL)
+                {
+                    buf->printf("%llu", uval);
+                    return;
+                }
+            }
+        }
+        expToBuffer(e, PREC_assign);
+    }
+
+    /**************************************************
+     * Write expression out to buf, but wrap it
+     * in ( ) if its precedence is less than pr.
+     */
+    void expToBuffer(Expression *e, PREC pr)
+    {
+    #ifdef DEBUG
+        if (precedence[e->op] == PREC_zero)
+            printf("precedence not defined for token '%s'\n", Token::tochars[e->op]);
+    #endif
+        assert(precedence[e->op] != PREC_zero);
+        assert(pr != PREC_zero);
+
+        //if (precedence[e->op] == 0) e->print();
+        /* Despite precedence, we don't allow a<b<c expressions.
+         * They must be parenthesized.
+         */
+        if (precedence[e->op] < pr ||
+            (pr == PREC_rel && precedence[e->op] == pr))
+        {
+            buf->writeByte('(');
+            e->accept(this);
+            buf->writeByte(')');
+        }
+        else
+            e->accept(this);
+    }
+
+    void visit(Expression *e)
+    {
+        buf->writestring(Token::toChars(e->op));
+    }
+
+    void visit(IntegerExp *e)
+    {
+        dinteger_t v = e->toInteger();
+
+        if (e->type)
+        {
+            Type *t = e->type;
+        L1:
+            switch (t->ty)
+            {
+                case Tenum:
+                {
+                    TypeEnum *te = (TypeEnum *)t;
+                    if (hgs->fullDump)
+                    {
+                        EnumDeclaration *sym = te->sym;
+                        if (inEnumDecl != sym)
+                        {
+                            for (size_t i = 0; i < sym->members->dim; i++)
+                            {
+                                EnumMember *em = (EnumMember *)(*sym->members)[i];
+                                if (em->value()->toInteger() == v)
+                                {
+                                    buf->printf("%s.%s", sym->toChars(), em->ident->toChars());
+                                    return;
+                                }
+                            }
+                        }
+                    }
+                    buf->printf("cast(%s)", te->sym->toChars());
+                    t = te->sym->memtype;
+                    goto L1;
+                }
+
+                case Twchar:        // BUG: need to cast(wchar)
+                case Tdchar:        // BUG: need to cast(dchar)
+                    if ((uinteger_t)v > 0xFF)
+                    {
+                        buf->printf("'\\U%08x'", v);
+                        break;
+                    }
+                case Tchar:
+                {
+                    size_t o = buf->offset;
+                    if (v == '\'')
+                        buf->writestring("'\\''");
+                    else if (isprint((int)v) && v != '\\')
+                        buf->printf("'%c'", (int)v);
+                    else
+                        buf->printf("'\\x%02x'", (int)v);
+                    if (hgs->ddoc)
+                        escapeDdocString(buf, o);
+                    break;
+                }
+
+                case Tint8:
+                    buf->writestring("cast(byte)");
+                    goto L2;
+
+                case Tint16:
+                    buf->writestring("cast(short)");
+                    goto L2;
+
+                case Tint32:
+                L2:
+                    buf->printf("%d", (int)v);
+                    break;
+
+                case Tuns8:
+                    buf->writestring("cast(ubyte)");
+                    goto L3;
+
+                case Tuns16:
+                    buf->writestring("cast(ushort)");
+                    goto L3;
+
+                case Tuns32:
+                L3:
+                    buf->printf("%uu", (unsigned)v);
+                    break;
+
+                case Tint64:
+                    buf->printf("%lldL", v);
+                    break;
+
+                case Tuns64:
+                L4:
+                    buf->printf("%lluLU", v);
+                    break;
+
+                case Tbool:
+                    buf->writestring(v ? "true" : "false");
+                    break;
+
+                case Tpointer:
+                    buf->writestring("cast(");
+                    buf->writestring(t->toChars());
+                    buf->writeByte(')');
+                    if (Target::ptrsize == 4)
+                        goto L3;
+                    else if (Target::ptrsize == 8)
+                        goto L4;
+                    else
+                        assert(0);
+
+                default:
+                    /* This can happen if errors, such as
+                     * the type is painted on like in fromConstInitializer().
+                     */
+                    if (!global.errors)
+                    {
+    #ifdef DEBUG
+                        t->print();
+    #endif
+                        assert(0);
+                    }
+                    break;
+            }
+        }
+        else if (v & 0x8000000000000000LL)
+            buf->printf("0x%llx", v);
+        else
+            buf->printf("%lld", v);
+    }
+
+    void visit(ErrorExp *e)
+    {
+        buf->writestring("__error");
+    }
+
+    void floatToBuffer(Type *type, real_t value)
+    {
+        /** sizeof(value)*3 is because each byte of mantissa is max
+        of 256 (3 characters). The string will be "-M.MMMMe-4932".
+        (ie, 8 chars more than mantissa). Plus one for trailing \0.
+        Plus one for rounding. */
+        const size_t BUFFER_LEN = sizeof(value) * 3 + 8 + 1 + 1;
+        char buffer[BUFFER_LEN];
+        CTFloat::sprint(buffer, 'g', value);
+        assert(strlen(buffer) < BUFFER_LEN);
+
+        if (hgs->hdrgen)
+        {
+            real_t r = CTFloat::parse(buffer);
+            if (r != value)                     // if exact duplication
+                CTFloat::sprint(buffer, 'a', value);
+        }
+        buf->writestring(buffer);
+
+        if (type)
+        {
+            Type *t = type->toBasetype();
+            switch (t->ty)
+            {
+                case Tfloat32:
+                case Timaginary32:
+                case Tcomplex32:
+                    buf->writeByte('F');
+                    break;
+
+                case Tfloat80:
+                case Timaginary80:
+                case Tcomplex80:
+                    buf->writeByte('L');
+                    break;
+
+                default:
+                    break;
+            }
+            if (t->isimaginary())
+                buf->writeByte('i');
+        }
+    }
+
+    void visit(RealExp *e)
+    {
+        floatToBuffer(e->type, e->value);
+    }
+
+    void visit(ComplexExp *e)
+    {
+        /* Print as:
+         *  (re+imi)
+         */
+        buf->writeByte('(');
+        floatToBuffer(e->type, creall(e->value));
+        buf->writeByte('+');
+        floatToBuffer(e->type, cimagl(e->value));
+        buf->writestring("i)");
+    }
+
+    void visit(IdentifierExp *e)
+    {
+        if (hgs->hdrgen || hgs->ddoc)
+            buf->writestring(e->ident->toHChars2());
+        else
+            buf->writestring(e->ident->toChars());
+    }
+
+    void visit(DsymbolExp *e)
+    {
+        buf->writestring(e->s->toChars());
+    }
+
+    void visit(ThisExp *e)
+    {
+        buf->writestring("this");
+    }
+
+    void visit(SuperExp *e)
+    {
+        buf->writestring("super");
+    }
+
+    void visit(NullExp *e)
+    {
+        buf->writestring("null");
+    }
+
+    void visit(StringExp *e)
+    {
+        buf->writeByte('"');
+        size_t o = buf->offset;
+        for (size_t i = 0; i < e->len; i++)
+        {
+            unsigned c = e->charAt(i);
+            switch (c)
+            {
+                case '"':
+                case '\\':
+                    buf->writeByte('\\');
+                default:
+                    if (c <= 0xFF)
+                    {
+                        if (c <= 0x7F && isprint(c))
+                            buf->writeByte(c);
+                        else
+                            buf->printf("\\x%02x", c);
+                    }
+                    else if (c <= 0xFFFF)
+                        buf->printf("\\x%02x\\x%02x", c & 0xFF, c >> 8);
+                    else
+                        buf->printf("\\x%02x\\x%02x\\x%02x\\x%02x",
+                            c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24);
+                    break;
+            }
+        }
+        if (hgs->ddoc)
+            escapeDdocString(buf, o);
+        buf->writeByte('"');
+        if (e->postfix)
+            buf->writeByte(e->postfix);
+    }
+
+    void visit(ArrayLiteralExp *e)
+    {
+        buf->writeByte('[');
+        argsToBuffer(e->elements, e->basis);
+        buf->writeByte(']');
+    }
+
+    void visit(AssocArrayLiteralExp *e)
+    {
+        buf->writeByte('[');
+        for (size_t i = 0; i < e->keys->dim; i++)
+        {
+            Expression *key = (*e->keys)[i];
+            Expression *value = (*e->values)[i];
+
+            if (i)
+                buf->writestring(", ");
+            expToBuffer(key, PREC_assign);
+            buf->writeByte(':');
+            expToBuffer(value, PREC_assign);
+        }
+        buf->writeByte(']');
+    }
+
+    void visit(StructLiteralExp *e)
+    {
+        buf->writestring(e->sd->toChars());
+        buf->writeByte('(');
+
+        // CTFE can generate struct literals that contain an AddrExp pointing
+        // to themselves, need to avoid infinite recursion:
+        // struct S { this(int){ this.s = &this; } S* s; }
+        // const foo = new S(0);
+        if (e->stageflags & stageToCBuffer)
+            buf->writestring("<recursion>");
+        else
+        {
+            int old = e->stageflags;
+            e->stageflags |= stageToCBuffer;
+            argsToBuffer(e->elements);
+            e->stageflags = old;
+        }
+
+        buf->writeByte(')');
+    }
+
+    void visit(TypeExp *e)
+    {
+        typeToBuffer(e->type, NULL);
+    }
+
+    void visit(ScopeExp *e)
+    {
+        if (e->sds->isTemplateInstance())
+        {
+            e->sds->accept(this);
+        }
+        else if (hgs != NULL && hgs->ddoc)
+        {
+            // fixes bug 6491
+            Module *m = e->sds->isModule();
+            if (m)
+                buf->writestring(m->md->toChars());
+            else
+                buf->writestring(e->sds->toChars());
+        }
+        else
+        {
+            buf->writestring(e->sds->kind());
+            buf->writeByte(' ');
+            buf->writestring(e->sds->toChars());
+        }
+    }
+
+    void visit(TemplateExp *e)
+    {
+        buf->writestring(e->td->toChars());
+    }
+
+    void visit(NewExp *e)
+    {
+        if (e->thisexp)
+        {
+            expToBuffer(e->thisexp, PREC_primary);
+            buf->writeByte('.');
+        }
+        buf->writestring("new ");
+        if (e->newargs && e->newargs->dim)
+        {
+            buf->writeByte('(');
+            argsToBuffer(e->newargs);
+            buf->writeByte(')');
+        }
+        typeToBuffer(e->newtype, NULL);
+        if (e->arguments && e->arguments->dim)
+        {
+            buf->writeByte('(');
+            argsToBuffer(e->arguments);
+            buf->writeByte(')');
+        }
+    }
+
+    void visit(NewAnonClassExp *e)
+    {
+        if (e->thisexp)
+        {
+            expToBuffer(e->thisexp, PREC_primary);
+            buf->writeByte('.');
+        }
+        buf->writestring("new");
+        if (e->newargs && e->newargs->dim)
+        {
+            buf->writeByte('(');
+            argsToBuffer(e->newargs);
+            buf->writeByte(')');
+        }
+        buf->writestring(" class ");
+        if (e->arguments && e->arguments->dim)
+        {
+            buf->writeByte('(');
+            argsToBuffer(e->arguments);
+            buf->writeByte(')');
+        }
+        if (e->cd)
+            e->cd->accept(this);
+    }
+
+    void visit(SymOffExp *e)
+    {
+        if (e->offset)
+            buf->printf("(& %s+%u)", e->var->toChars(), e->offset);
+        else if (e->var->isTypeInfoDeclaration())
+            buf->printf("%s", e->var->toChars());
+        else
+            buf->printf("& %s", e->var->toChars());
+    }
+
+    void visit(VarExp *e)
+    {
+        buf->writestring(e->var->toChars());
+    }
+
+    void visit(OverExp *e)
+    {
+        buf->writestring(e->vars->ident->toChars());
+    }
+
+    void visit(TupleExp *e)
+    {
+        if (e->e0)
+        {
+            buf->writeByte('(');
+            e->e0->accept(this);
+            buf->writestring(", tuple(");
+            argsToBuffer(e->exps);
+            buf->writestring("))");
+        }
+        else
+        {
+            buf->writestring("tuple(");
+            argsToBuffer(e->exps);
+            buf->writeByte(')');
+        }
+    }
+
+    void visit(FuncExp *e)
+    {
+        e->fd->accept(this);
+        //buf->writestring(e->fd->toChars());
+    }
+
+    void visit(DeclarationExp *e)
+    {
+        /* Normal dmd execution won't reach here - regular variable declarations
+         * are handled in visit(ExpStatement), so here would be used only when
+         * we'll directly call Expression::toChars() for debugging.
+         */
+        if (VarDeclaration *v = e->declaration->isVarDeclaration())
+        {
+            // For debugging use:
+            // - Avoid printing newline.
+            // - Intentionally use the format (Type var;)
+            //   which isn't correct as regular D code.
+            buf->writeByte('(');
+            visitVarDecl(v, false);
+            buf->writeByte(';');
+            buf->writeByte(')');
+        }
+        else
+            e->declaration->accept(this);
+    }
+
+    void visit(TypeidExp *e)
+    {
+        buf->writestring("typeid(");
+        objectToBuffer(e->obj);
+        buf->writeByte(')');
+    }
+
+    void visit(TraitsExp *e)
+    {
+        buf->writestring("__traits(");
+        buf->writestring(e->ident->toChars());
+        if (e->args)
+        {
+            for (size_t i = 0; i < e->args->dim; i++)
+            {
+                RootObject *arg = (*e->args)[i];
+                buf->writestring(", ");
+                objectToBuffer(arg);
+            }
+        }
+        buf->writeByte(')');
+    }
+
+    void visit(HaltExp *e)
+    {
+        buf->writestring("halt");
+    }
+
+    void visit(IsExp *e)
+    {
+        buf->writestring("is(");
+        typeToBuffer(e->targ, e->id);
+        if (e->tok2 != TOKreserved)
+        {
+            buf->printf(" %s %s", Token::toChars(e->tok), Token::toChars(e->tok2));
+        }
+        else if (e->tspec)
+        {
+            if (e->tok == TOKcolon)
+                buf->writestring(" : ");
+            else
+                buf->writestring(" == ");
+            typeToBuffer(e->tspec, NULL);
+        }
+        if (e->parameters && e->parameters->dim)
+        {
+            buf->writestring(", ");
+            visitTemplateParameters(e->parameters);
+        }
+        buf->writeByte(')');
+    }
+
+    void visit(UnaExp *e)
+    {
+        buf->writestring(Token::toChars(e->op));
+        expToBuffer(e->e1, precedence[e->op]);
+    }
+
+    void visit(BinExp *e)
+    {
+        expToBuffer(e->e1, precedence[e->op]);
+        buf->writeByte(' ');
+        buf->writestring(Token::toChars(e->op));
+        buf->writeByte(' ');
+        expToBuffer(e->e2, (PREC)(precedence[e->op] + 1));
+    }
+
+    void visit(CompileExp *e)
+    {
+        buf->writestring("mixin(");
+        expToBuffer(e->e1, PREC_assign);
+        buf->writeByte(')');
+    }
+
+    void visit(ImportExp *e)
+    {
+        buf->writestring("import(");
+        expToBuffer(e->e1, PREC_assign);
+        buf->writeByte(')');
+    }
+
+    void visit(AssertExp *e)
+    {
+        buf->writestring("assert(");
+        expToBuffer(e->e1, PREC_assign);
+        if (e->msg)
+        {
+            buf->writestring(", ");
+            expToBuffer(e->msg, PREC_assign);
+        }
+        buf->writeByte(')');
+    }
+
+    void visit(DotIdExp *e)
+    {
+        expToBuffer(e->e1, PREC_primary);
+        buf->writeByte('.');
+        buf->writestring(e->ident->toChars());
+    }
+
+    void visit(DotTemplateExp *e)
+    {
+        expToBuffer(e->e1, PREC_primary);
+        buf->writeByte('.');
+        buf->writestring(e->td->toChars());
+    }
+
+    void visit(DotVarExp *e)
+    {
+        expToBuffer(e->e1, PREC_primary);
+        buf->writeByte('.');
+        buf->writestring(e->var->toChars());
+    }
+
+    void visit(DotTemplateInstanceExp *e)
+    {
+        expToBuffer(e->e1, PREC_primary);
+        buf->writeByte('.');
+        e->ti->accept(this);
+    }
+
+    void visit(DelegateExp *e)
+    {
+        buf->writeByte('&');
+        if (!e->func->isNested())
+        {
+            expToBuffer(e->e1, PREC_primary);
+            buf->writeByte('.');
+        }
+        buf->writestring(e->func->toChars());
+    }
+
+    void visit(DotTypeExp *e)
+    {
+        expToBuffer(e->e1, PREC_primary);
+        buf->writeByte('.');
+        buf->writestring(e->sym->toChars());
+    }
+
+    void visit(CallExp *e)
+    {
+        if (e->e1->op == TOKtype)
+        {
+            /* Avoid parens around type to prevent forbidden cast syntax:
+             *   (sometype)(arg1)
+             * This is ok since types in constructor calls
+             * can never depend on parens anyway
+             */
+            e->e1->accept(this);
+        }
+        else
+            expToBuffer(e->e1, precedence[e->op]);
+        buf->writeByte('(');
+        argsToBuffer(e->arguments);
+        buf->writeByte(')');
+    }
+
+    void visit(PtrExp *e)
+    {
+        buf->writeByte('*');
+        expToBuffer(e->e1, precedence[e->op]);
+    }
+
+    void visit(DeleteExp *e)
+    {
+        buf->writestring("delete ");
+        expToBuffer(e->e1, precedence[e->op]);
+    }
+
+    void visit(CastExp *e)
+    {
+        buf->writestring("cast(");
+        if (e->to)
+            typeToBuffer(e->to, NULL);
+        else
+        {
+            MODtoBuffer(buf, e->mod);
+        }
+        buf->writeByte(')');
+        expToBuffer(e->e1, precedence[e->op]);
+    }
+
+    void visit(VectorExp *e)
+    {
+        buf->writestring("cast(");
+        typeToBuffer(e->to, NULL);
+        buf->writeByte(')');
+        expToBuffer(e->e1, precedence[e->op]);
+    }
+
+    void visit(SliceExp *e)
+    {
+        expToBuffer(e->e1, precedence[e->op]);
+        buf->writeByte('[');
+        if (e->upr || e->lwr)
+        {
+            if (e->lwr)
+                sizeToBuffer(e->lwr);
+            else
+                buf->writeByte('0');
+            buf->writestring("..");
+            if (e->upr)
+                sizeToBuffer(e->upr);
+            else
+                buf->writeByte('$');
+        }
+        buf->writeByte(']');
+    }
+
+    void visit(ArrayLengthExp *e)
+    {
+        expToBuffer(e->e1, PREC_primary);
+        buf->writestring(".length");
+    }
+
+    void visit(IntervalExp *e)
+    {
+        expToBuffer(e->lwr, PREC_assign);
+        buf->writestring("..");
+        expToBuffer(e->upr, PREC_assign);
+    }
+
+    void visit(DelegatePtrExp *e)
+    {
+        expToBuffer(e->e1, PREC_primary);
+        buf->writestring(".ptr");
+    }
+
+    void visit(DelegateFuncptrExp *e)
+    {
+        expToBuffer(e->e1, PREC_primary);
+        buf->writestring(".funcptr");
+    }
+
+    void visit(ArrayExp *e)
+    {
+        expToBuffer(e->e1, PREC_primary);
+        buf->writeByte('[');
+        argsToBuffer(e->arguments);
+        buf->writeByte(']');
+    }
+
+    void visit(DotExp *e)
+    {
+        expToBuffer(e->e1, PREC_primary);
+        buf->writeByte('.');
+        expToBuffer(e->e2, PREC_primary);
+    }
+
+    void visit(IndexExp *e)
+    {
+        expToBuffer(e->e1, PREC_primary);
+        buf->writeByte('[');
+        sizeToBuffer(e->e2);
+        buf->writeByte(']');
+    }
+
+    void visit(PostExp *e)
+    {
+        expToBuffer(e->e1, precedence[e->op]);
+        buf->writestring(Token::toChars(e->op));
+    }
+
+    void visit(PreExp *e)
+    {
+        buf->writestring(Token::toChars(e->op));
+        expToBuffer(e->e1, precedence[e->op]);
+    }
+
+    void visit(RemoveExp *e)
+    {
+        expToBuffer(e->e1, PREC_primary);
+        buf->writestring(".remove(");
+        expToBuffer(e->e2, PREC_assign);
+        buf->writeByte(')');
+    }
+
+    void visit(CondExp *e)
+    {
+        expToBuffer(e->econd, PREC_oror);
+        buf->writestring(" ? ");
+        expToBuffer(e->e1, PREC_expr);
+        buf->writestring(" : ");
+        expToBuffer(e->e2, PREC_cond);
+    }
+
+    void visit(DefaultInitExp *e)
+    {
+        buf->writestring(Token::toChars(e->subop));
+    }
+
+    void visit(ClassReferenceExp *e)
+    {
+        buf->writestring(e->value->toChars());
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    void visit(TemplateTypeParameter *tp)
+    {
+        buf->writestring(tp->ident->toChars());
+        if (tp->specType)
+        {
+            buf->writestring(" : ");
+            typeToBuffer(tp->specType, NULL);
+        }
+        if (tp->defaultType)
+        {
+            buf->writestring(" = ");
+            typeToBuffer(tp->defaultType, NULL);
+        }
+    }
+
+    void visit(TemplateThisParameter *tp)
+    {
+        buf->writestring("this ");
+        visit((TemplateTypeParameter *)tp);
+    }
+
+    void visit(TemplateAliasParameter *tp)
+    {
+        buf->writestring("alias ");
+        if (tp->specType)
+            typeToBuffer(tp->specType, tp->ident);
+        else
+            buf->writestring(tp->ident->toChars());
+        if (tp->specAlias)
+        {
+            buf->writestring(" : ");
+            objectToBuffer(tp->specAlias);
+        }
+        if (tp->defaultAlias)
+        {
+            buf->writestring(" = ");
+            objectToBuffer(tp->defaultAlias);
+        }
+    }
+
+    void visit(TemplateValueParameter *tp)
+    {
+        typeToBuffer(tp->valType, tp->ident);
+        if (tp->specValue)
+        {
+            buf->writestring(" : ");
+            tp->specValue->accept(this);
+        }
+        if (tp->defaultValue)
+        {
+            buf->writestring(" = ");
+            tp->defaultValue->accept(this);
+        }
+    }
+
+    void visit(TemplateTupleParameter *tp)
+    {
+        buf->writestring(tp->ident->toChars());
+        buf->writestring("...");
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    void visit(DebugCondition *c)
+    {
+        if (c->ident)
+            buf->printf("debug (%s)", c->ident->toChars());
+        else
+            buf->printf("debug (%u)", c->level);
+    }
+
+    void visit(VersionCondition *c)
+    {
+        if (c->ident)
+            buf->printf("version (%s)", c->ident->toChars());
+        else
+            buf->printf("version (%u)", c->level);
+    }
+
+    void visit(StaticIfCondition *c)
+    {
+        buf->writestring("static if (");
+        c->exp->accept(this);
+        buf->writeByte(')');
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    void visit(Parameter *p)
+    {
+        if (p->storageClass & STCauto)
+            buf->writestring("auto ");
+
+        if (p->storageClass & STCreturn)
+            buf->writestring("return ");
+
+        if (p->storageClass & STCout)
+            buf->writestring("out ");
+        else if (p->storageClass & STCref)
+            buf->writestring("ref ");
+        else if (p->storageClass & STCin)
+            buf->writestring("in ");
+        else if (p->storageClass & STClazy)
+            buf->writestring("lazy ");
+        else if (p->storageClass & STCalias)
+            buf->writestring("alias ");
+
+        StorageClass stc = p->storageClass;
+        if (p->type && p->type->mod & MODshared)
+            stc &= ~STCshared;
+
+        if (stcToBuffer(buf, stc & (STCconst | STCimmutable | STCwild | STCshared | STCscope | STCscopeinferred)))
+            buf->writeByte(' ');
+
+        if (p->storageClass & STCalias)
+        {
+            if (p->ident)
+                buf->writestring(p->ident->toChars());
+        }
+        else if (p->type->ty == Tident &&
+                 strlen(((TypeIdentifier *)p->type)->ident->toChars()) > 3 &&
+                 strncmp(((TypeIdentifier *)p->type)->ident->toChars(), "__T", 3) == 0)
+        {
+            // print parameter name, instead of undetermined type parameter
+            buf->writestring(p->ident->toChars());
+        }
+        else
+            typeToBuffer(p->type, p->ident);
+        if (p->defaultArg)
+        {
+            buf->writestring(" = ");
+            p->defaultArg->accept(this);
+        }
+    }
+
+    void parametersToBuffer(Parameters *parameters, int varargs)
+    {
+        buf->writeByte('(');
+        if (parameters)
+        {
+            size_t dim = Parameter::dim(parameters);
+            for (size_t i = 0; i < dim; i++)
+            {
+                if (i)
+                    buf->writestring(", ");
+                Parameter *fparam = Parameter::getNth(parameters, i);
+                fparam->accept(this);
+            }
+            if (varargs)
+            {
+                if (parameters->dim && varargs == 1)
+                    buf->writestring(", ");
+                buf->writestring("...");
+            }
+        }
+        buf->writeByte(')');
+    }
+
+    void visit(Module *m)
+    {
+        if (m->md)
+        {
+            if (m->userAttribDecl)
+            {
+                buf->writestring("@(");
+                argsToBuffer(m->userAttribDecl->atts);
+                buf->writeByte(')');
+                buf->writenl();
+            }
+            if (m->md->isdeprecated)
+            {
+                if (m->md->msg)
+                {
+                    buf->writestring("deprecated(");
+                    m->md->msg->accept(this);
+                    buf->writestring(") ");
+                }
+                else
+                    buf->writestring("deprecated ");
+            }
+
+            buf->writestring("module ");
+            buf->writestring(m->md->toChars());
+            buf->writeByte(';');
+            buf->writenl();
+        }
+        for (size_t i = 0; i < m->members->dim; i++)
+        {
+            Dsymbol *s = (*m->members)[i];
+            s->accept(this);
+        }
+    }
+};
+
+void toCBuffer(Statement *s, OutBuffer *buf, HdrGenState *hgs)
+{
+    PrettyPrintVisitor v(buf, hgs);
+    s->accept(&v);
+}
+
+void toCBuffer(Type *t, OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    PrettyPrintVisitor v(buf, hgs);
+    v.typeToBuffer(t, ident);
+}
+
+void toCBuffer(Dsymbol *s, OutBuffer *buf, HdrGenState *hgs)
+{
+    PrettyPrintVisitor v(buf, hgs);
+    s->accept(&v);
+}
+
+// used from TemplateInstance::toChars() and TemplateMixin::toChars()
+void toCBufferInstance(TemplateInstance *ti, OutBuffer *buf, bool qualifyTypes)
+{
+    HdrGenState hgs;
+    hgs.fullQual = qualifyTypes;
+    PrettyPrintVisitor v(buf, &hgs);
+    v.visit(ti);
+}
+
+void toCBuffer(Initializer *iz, OutBuffer *buf, HdrGenState *hgs)
+{
+    PrettyPrintVisitor v(buf, hgs);
+    iz->accept(&v);
+}
+
+bool stcToBuffer(OutBuffer *buf, StorageClass stc)
+{
+    bool result = false;
+    if ((stc & (STCreturn | STCscope)) == (STCreturn | STCscope))
+        stc &= ~STCscope;
+    if (stc & STCscopeinferred)
+        stc &= ~(STCscope | STCscopeinferred);
+    while (stc)
+    {
+        const char *p = stcToChars(stc);
+        if (!p)
+            break;
+        if (!result)
+            result = true;
+        else
+            buf->writeByte(' ');
+        buf->writestring(p);
+    }
+    return result;
+}
+
+/*************************************************
+ * Pick off one of the storage classes from stc,
+ * and return a pointer to a string representation of it.
+ * stc is reduced by the one picked.
+ */
+const char *stcToChars(StorageClass& stc)
+{
+    struct SCstring
+    {
+        StorageClass stc;
+        TOK tok;
+        const char *id;
+    };
+
+    static SCstring table[] =
+    {
+        { STCauto,         TOKauto },
+        { STCscope,        TOKscope },
+        { STCstatic,       TOKstatic },
+        { STCextern,       TOKextern },
+        { STCconst,        TOKconst },
+        { STCfinal,        TOKfinal },
+        { STCabstract,     TOKabstract },
+        { STCsynchronized, TOKsynchronized },
+        { STCdeprecated,   TOKdeprecated },
+        { STCoverride,     TOKoverride },
+        { STClazy,         TOKlazy },
+        { STCalias,        TOKalias },
+        { STCout,          TOKout },
+        { STCin,           TOKin },
+        { STCmanifest,     TOKenum },
+        { STCimmutable,    TOKimmutable },
+        { STCshared,       TOKshared },
+        { STCnothrow,      TOKnothrow },
+        { STCwild,         TOKwild },
+        { STCpure,         TOKpure },
+        { STCref,          TOKref },
+        { STCtls },
+        { STCgshared,      TOKgshared },
+        { STCnogc,         TOKat,       "@nogc" },
+        { STCproperty,     TOKat,       "@property" },
+        { STCsafe,         TOKat,       "@safe" },
+        { STCtrusted,      TOKat,       "@trusted" },
+        { STCsystem,       TOKat,       "@system" },
+        { STCdisable,      TOKat,       "@disable" },
+        { 0,               TOKreserved }
+    };
+
+    for (int i = 0; table[i].stc; i++)
+    {
+        StorageClass tbl = table[i].stc;
+        assert(tbl & STCStorageClass);
+        if (stc & tbl)
+        {
+            stc &= ~tbl;
+            if (tbl == STCtls)  // TOKtls was removed
+                return "__thread";
+
+            TOK tok = table[i].tok;
+            if (tok == TOKat)
+                return table[i].id;
+            else
+                return Token::toChars(tok);
+        }
+    }
+    //printf("stc = %llx\n", stc);
+    return NULL;
+}
+
+void trustToBuffer(OutBuffer *buf, TRUST trust)
+{
+    const char *p = trustToChars(trust);
+    if (p)
+        buf->writestring(p);
+}
+
+const char *trustToChars(TRUST trust)
+{
+    switch (trust)
+    {
+        case TRUSTdefault:  return NULL;
+        case TRUSTsystem:   return "@system";
+        case TRUSTtrusted:  return "@trusted";
+        case TRUSTsafe:     return "@safe";
+        default:            assert(0);
+    }
+    return NULL;    // never reached
+}
+
+void linkageToBuffer(OutBuffer *buf, LINK linkage)
+{
+    const char *p = linkageToChars(linkage);
+    if (p)
+    {
+        buf->writestring("extern (");
+        buf->writestring(p);
+        buf->writeByte(')');
+    }
+}
+
+const char *linkageToChars(LINK linkage)
+{
+    switch (linkage)
+    {
+        case LINKdefault:   return NULL;
+        case LINKd:         return "D";
+        case LINKc:         return "C";
+        case LINKcpp:       return "C++";
+        case LINKwindows:   return "Windows";
+        case LINKpascal:    return "Pascal";
+        case LINKobjc:      return "Objective-C";
+        case LINKsystem:    return "System";
+        default:            assert(0);
+    }
+    return NULL;    // never reached
+}
+
+void protectionToBuffer(OutBuffer *buf, Prot prot)
+{
+    const char *p = protectionToChars(prot.kind);
+    if (p)
+        buf->writestring(p);
+
+    if (prot.kind == PROTpackage && prot.pkg)
+    {
+        buf->writeByte('(');
+        buf->writestring(prot.pkg->toPrettyChars(true));
+        buf->writeByte(')');
+    }
+}
+
+const char *protectionToChars(PROTKIND kind)
+{
+    switch (kind)
+    {
+        case PROTundefined: return NULL;
+        case PROTnone:      return "none";
+        case PROTprivate:   return "private";
+        case PROTpackage:   return "package";
+        case PROTprotected: return "protected";
+        case PROTpublic:    return "public";
+        case PROTexport:    return "export";
+        default:            assert(0);
+    }
+    return NULL;    // never reached
+}
+
+// Print the full function signature with correct ident, attributes and template args
+void functionToBufferFull(TypeFunction *tf, OutBuffer *buf, Identifier *ident,
+        HdrGenState* hgs, TemplateDeclaration *td)
+{
+    //printf("TypeFunction::toCBuffer() this = %p\n", this);
+    PrettyPrintVisitor v(buf, hgs);
+    v.visitFuncIdentWithPrefix(tf, ident, td, true);
+}
+
+// ident is inserted before the argument list and will be "function" or "delegate" for a type
+void functionToBufferWithIdent(TypeFunction *tf, OutBuffer *buf, const char *ident)
+{
+    HdrGenState hgs;
+    PrettyPrintVisitor v(buf, &hgs);
+    v.visitFuncIdentWithPostfix(tf, ident);
+}
+
+void toCBuffer(Expression *e, OutBuffer *buf, HdrGenState *hgs)
+{
+    PrettyPrintVisitor v(buf, hgs);
+    e->accept(&v);
+}
+
+/**************************************************
+ * Write out argument types to buf.
+ */
+void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments)
+{
+    if (!arguments || !arguments->dim)
+        return;
+
+    HdrGenState hgs;
+    PrettyPrintVisitor v(buf, &hgs);
+    for (size_t i = 0; i < arguments->dim; i++)
+    {
+        Expression *arg = (*arguments)[i];
+        if (i)
+            buf->writestring(", ");
+        v.typeToBuffer(arg->type, NULL);
+    }
+}
+
+void toCBuffer(TemplateParameter *tp, OutBuffer *buf, HdrGenState *hgs)
+{
+    PrettyPrintVisitor v(buf, hgs);
+    tp->accept(&v);
+}
+
+void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects)
+{
+    if (!objects || !objects->dim)
+        return;
+
+    HdrGenState hgs;
+    PrettyPrintVisitor v(buf, &hgs);
+    for (size_t i = 0; i < objects->dim; i++)
+    {
+        RootObject *o = (*objects)[i];
+        if (i)
+            buf->writestring(", ");
+        v.objectToBuffer(o);
+    }
+}
+
+const char *parametersTypeToChars(Parameters *parameters, int varargs)
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+    PrettyPrintVisitor v(&buf, &hgs);
+    v.parametersToBuffer(parameters, varargs);
+    return buf.extractString();
+}
diff --git a/gcc/d/dfrontend/hdrgen.h b/gcc/d/dfrontend/hdrgen.h
new file mode 100644
index 00000000000..e698ae0117b
--- /dev/null
+++ b/gcc/d/dfrontend/hdrgen.h
@@ -0,0 +1,51 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Dave Fladebo
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/expression.h
+ */
+
+#include <string.h>                     // memset()
+
+#include "dsymbol.h"
+
+void genhdrfile(Module *m);
+
+struct HdrGenState
+{
+    bool hdrgen;        // true if generating header file
+    bool ddoc;          // true if generating Ddoc file
+    bool fullDump;      // true if generating a full AST dump file
+    bool fullQual;      // fully qualify types when printing
+    int tpltMember;
+    int autoMember;
+    int forStmtInit;
+
+    HdrGenState() { memset(this, 0, sizeof(HdrGenState)); }
+};
+
+void toCBuffer(Statement *s, OutBuffer *buf, HdrGenState *hgs);
+void toCBuffer(Type *t, OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+void toCBuffer(Dsymbol *s, OutBuffer *buf, HdrGenState *hgs);
+void toCBuffer(Initializer *iz, OutBuffer *buf, HdrGenState *hgs);
+void toCBuffer(Expression *e, OutBuffer *buf, HdrGenState *hgs);
+void toCBuffer(TemplateParameter *tp, OutBuffer *buf, HdrGenState *hgs);
+
+void toCBufferInstance(TemplateInstance *ti, OutBuffer *buf, bool qualifyTypes = false);
+
+void functionToBufferFull(TypeFunction *tf, OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TemplateDeclaration *td);
+void functionToBufferWithIdent(TypeFunction *t, OutBuffer *buf, const char *ident);
+
+void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments);
+
+void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects);
+
+const char *parametersTypeToChars(Parameters *parameters, int varargs);
+
+bool stcToBuffer(OutBuffer *buf, StorageClass stc);
+const char *stcToChars(StorageClass& stc);
+const char *linkageToChars(LINK linkage);
diff --git a/gcc/d/dfrontend/identifier.c b/gcc/d/dfrontend/identifier.c
new file mode 100644
index 00000000000..ed80bf1daa8
--- /dev/null
+++ b/gcc/d/dfrontend/identifier.c
@@ -0,0 +1,191 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/identifier.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "root.h"
+#include "identifier.h"
+#include "mars.h"
+#include "id.h"
+#include "tokens.h"
+#include "utf.h"
+
+Identifier::Identifier(const char *string, size_t length, int value)
+{
+    //printf("Identifier('%s', %d)\n", string, value);
+    this->string = string;
+    this->value = value;
+    this->len = length;
+}
+
+Identifier::Identifier(const char *string)
+{
+    //printf("Identifier('%s')\n", string);
+    this->string = string;
+    this->value = TOKidentifier;
+    this->len = strlen(string);
+}
+
+Identifier *Identifier::create(const char *string)
+{
+    return new Identifier(string);
+}
+
+bool Identifier::equals(RootObject *o)
+{
+    return this == o || strncmp(string,o->toChars(),len+1) == 0;
+}
+
+int Identifier::compare(RootObject *o)
+{
+    return strncmp(string, o->toChars(), len + 1);
+}
+
+const char *Identifier::toChars()
+{
+    return (char *)string;
+}
+
+int Identifier::getValue() const
+{
+    return value;
+}
+
+const char *Identifier::toHChars2()
+{
+    const char *p = NULL;
+
+    if (this == Id::ctor) p = "this";
+    else if (this == Id::dtor) p = "~this";
+    else if (this == Id::unitTest) p = "unittest";
+    else if (this == Id::dollar) p = "$";
+    else if (this == Id::withSym) p = "with";
+    else if (this == Id::result) p = "result";
+    else if (this == Id::returnLabel) p = "return";
+    else
+    {   p = toChars();
+        if (*p == '_')
+        {
+            if (strncmp(p, "_staticCtor", 11) == 0)
+                p = "static this";
+            else if (strncmp(p, "_staticDtor", 11) == 0)
+                p = "static ~this";
+            else if (strncmp(p, "__invariant", 11) == 0)
+                p = "invariant";
+        }
+    }
+
+    return p;
+}
+
+void Identifier::print()
+{
+    fprintf(stderr, "%s",string);
+}
+
+int Identifier::dyncast() const
+{
+    return DYNCAST_IDENTIFIER;
+}
+
+StringTable Identifier::stringtable;
+
+Identifier *Identifier::generateId(const char *prefix)
+{
+    static size_t i;
+
+    return generateId(prefix, ++i);
+}
+
+Identifier *Identifier::generateId(const char *prefix, size_t i)
+{   OutBuffer buf;
+
+    buf.writestring(prefix);
+    buf.printf("%llu", (ulonglong)i);
+
+    char *id = buf.peekString();
+    return idPool(id);
+}
+
+/********************************************
+ * Create an identifier in the string table.
+ */
+
+Identifier *Identifier::idPool(const char *s, size_t len)
+{
+    StringValue *sv = stringtable.update(s, len);
+    Identifier *id = (Identifier *) sv->ptrvalue;
+    if (!id)
+    {
+        id = new Identifier(sv->toDchars(), len, TOKidentifier);
+        sv->ptrvalue = (char *)id;
+    }
+    return id;
+}
+
+Identifier *Identifier::idPool(const char *s, size_t len, int value)
+{
+    StringValue *sv = stringtable.insert(s, len, NULL);
+    assert(sv);
+    Identifier *id = new Identifier(sv->toDchars(), len, value);
+    sv->ptrvalue = (char *)id;
+    return id;
+}
+
+/**********************************
+ * Determine if string is a valid Identifier.
+ * Returns:
+ *      0       invalid
+ */
+
+bool Identifier::isValidIdentifier(const char *p)
+{
+    size_t len;
+    size_t idx;
+
+    if (!p || !*p)
+        goto Linvalid;
+
+    if (*p >= '0' && *p <= '9')         // beware of isdigit() on signed chars
+        goto Linvalid;
+
+    len = strlen(p);
+    idx = 0;
+    while (p[idx])
+    {
+        dchar_t dc;
+        const char *q = utf_decodeChar((utf8_t *)p, len, &idx, &dc);
+        if (q)
+            goto Linvalid;
+
+        if (!((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_'))
+            goto Linvalid;
+    }
+    return true;
+
+Linvalid:
+    return false;
+}
+
+Identifier *Identifier::lookup(const char *s, size_t len)
+{
+    StringValue *sv = stringtable.lookup(s, len);
+    if (!sv)
+        return NULL;
+    return (Identifier *)sv->ptrvalue;
+}
+
+void Identifier::initTable()
+{
+    stringtable._init(28000);
+}
diff --git a/gcc/d/dfrontend/identifier.h b/gcc/d/dfrontend/identifier.h
new file mode 100644
index 00000000000..a2e53c0c279
--- /dev/null
+++ b/gcc/d/dfrontend/identifier.h
@@ -0,0 +1,57 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/identifier.h
+ */
+
+#ifndef DMD_IDENTIFIER_H
+#define DMD_IDENTIFIER_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "stringtable.h"
+
+class Identifier : public RootObject
+{
+private:
+    int value;
+    const char *string;
+    size_t len;
+
+public:
+    Identifier(const char *string, size_t length, int value);
+    Identifier(const char *string);
+    static Identifier* create(const char *string);
+    bool equals(RootObject *o);
+    int compare(RootObject *o);
+    void print();
+    const char *toChars();
+    int getValue() const;
+    const char *toHChars2();
+    int dyncast() const;
+
+    static StringTable stringtable;
+    static Identifier *generateId(const char *prefix);
+    static Identifier *generateId(const char *prefix, size_t i);
+    static Identifier *idPool(const char *s, size_t len);
+    static Identifier *idPool(const char *s, size_t len, int value);
+
+    static inline Identifier *idPool(const char *s)
+    {
+        return idPool(s, strlen(s));
+    }
+
+    static bool isValidIdentifier(const char *p);
+    static Identifier *lookup(const char *s, size_t len);
+    static void initTable();
+};
+
+#endif /* DMD_IDENTIFIER_H */
diff --git a/gcc/d/dfrontend/idgen.c b/gcc/d/dfrontend/idgen.c
new file mode 100644
index 00000000000..52aa0416a25
--- /dev/null
+++ b/gcc/d/dfrontend/idgen.c
@@ -0,0 +1,493 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/idgen.c
+ */
+
+// Program to generate string files in d data structures.
+// Saves much tedious typing, and eliminates typo problems.
+// Generates:
+//      id.h
+//      id.c
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+struct Msgtable
+{
+    const char* ident;      // name to use in DMD source
+    const char* name;       // name in D executable
+};
+
+Msgtable msgtable[] =
+{
+    { "IUnknown" },
+    { "Object" },
+    { "object" },
+    { "string" },
+    { "wstring" },
+    { "dstring" },
+    { "max" },
+    { "min" },
+    { "This", "this" },
+    { "_super", "super" },
+    { "ctor", "__ctor" },
+    { "dtor", "__dtor" },
+    { "__xdtor", "__xdtor" },
+    { "__fieldDtor", "__fieldDtor" },
+    { "__aggrDtor", "__aggrDtor" },
+    { "postblit", "__postblit" },
+    { "__xpostblit", "__xpostblit" },
+    { "__fieldPostblit", "__fieldPostblit" },
+    { "__aggrPostblit", "__aggrPostblit" },
+    { "classInvariant", "__invariant" },
+    { "unitTest", "__unitTest" },
+    { "require", "__require" },
+    { "ensure", "__ensure" },
+    { "_init", "init" },
+    { "__sizeof", "sizeof" },
+    { "__xalignof", "alignof" },
+    { "_mangleof", "mangleof" },
+    { "stringof" },
+    { "_tupleof", "tupleof" },
+    { "length" },
+    { "remove" },
+    { "ptr" },
+    { "array" },
+    { "funcptr" },
+    { "dollar", "__dollar" },
+    { "ctfe", "__ctfe" },
+    { "offset" },
+    { "offsetof" },
+    { "ModuleInfo" },
+    { "ClassInfo" },
+    { "classinfo" },
+    { "typeinfo" },
+    { "outer" },
+    { "Exception" },
+    { "RTInfo" },
+    { "Throwable" },
+    { "Error" },
+    { "withSym", "__withSym" },
+    { "result", "__result" },
+    { "returnLabel", "__returnLabel" },
+    { "line" },
+    { "empty", "" },
+    { "p" },
+    { "q" },
+    { "__vptr" },
+    { "__monitor" },
+    { "gate", "__gate" },
+    { "__c_long" },
+    { "__c_ulong" },
+    { "__c_long_double" },
+    { "cpp_type_info_ptr", "__cpp_type_info_ptr" },
+    { "_assert", "assert" },
+    { "_unittest", "unittest" },
+
+    { "TypeInfo" },
+    { "TypeInfo_Class" },
+    { "TypeInfo_Interface" },
+    { "TypeInfo_Struct" },
+    { "TypeInfo_Enum" },
+    { "TypeInfo_Pointer" },
+    { "TypeInfo_Vector" },
+    { "TypeInfo_Array" },
+    { "TypeInfo_StaticArray" },
+    { "TypeInfo_AssociativeArray" },
+    { "TypeInfo_Function" },
+    { "TypeInfo_Delegate" },
+    { "TypeInfo_Tuple" },
+    { "TypeInfo_Const" },
+    { "TypeInfo_Invariant" },
+    { "TypeInfo_Shared" },
+    { "TypeInfo_Wild", "TypeInfo_Inout" },
+    { "elements" },
+    { "_arguments_typeinfo" },
+    { "_arguments" },
+    { "_argptr" },
+    { "destroy" },
+    { "xopEquals", "__xopEquals" },
+    { "xopCmp", "__xopCmp" },
+    { "xtoHash", "__xtoHash" },
+
+    { "LINE", "__LINE__" },
+    { "FILE", "__FILE__" },
+    { "MODULE", "__MODULE__" },
+    { "FUNCTION", "__FUNCTION__" },
+    { "PRETTY_FUNCTION", "__PRETTY_FUNCTION__" },
+    { "DATE", "__DATE__" },
+    { "TIME", "__TIME__" },
+    { "TIMESTAMP", "__TIMESTAMP__" },
+    { "VENDOR", "__VENDOR__" },
+    { "VERSIONX", "__VERSION__" },
+    { "EOFX", "__EOF__" },
+
+    { "nan" },
+    { "infinity" },
+    { "dig" },
+    { "epsilon" },
+    { "mant_dig" },
+    { "max_10_exp" },
+    { "max_exp" },
+    { "min_10_exp" },
+    { "min_exp" },
+    { "min_normal" },
+    { "re" },
+    { "im" },
+
+    { "C" },
+    { "D" },
+    { "Windows" },
+    { "Pascal" },
+    { "System" },
+    { "Objective" },
+
+    { "exit" },
+    { "success" },
+    { "failure" },
+
+    { "keys" },
+    { "values" },
+    { "rehash" },
+
+    { "property" },
+    { "nogc" },
+    { "safe" },
+    { "trusted" },
+    { "system" },
+    { "disable" },
+
+    // For inline assembler
+    { "___out", "out" },
+    { "___in", "in" },
+    { "__int", "int" },
+    { "_dollar", "$" },
+    { "__LOCAL_SIZE" },
+
+    // For operator overloads
+    { "uadd",    "opPos" },
+    { "neg",     "opNeg" },
+    { "com",     "opCom" },
+    { "add",     "opAdd" },
+    { "add_r",   "opAdd_r" },
+    { "sub",     "opSub" },
+    { "sub_r",   "opSub_r" },
+    { "mul",     "opMul" },
+    { "mul_r",   "opMul_r" },
+    { "div",     "opDiv" },
+    { "div_r",   "opDiv_r" },
+    { "mod",     "opMod" },
+    { "mod_r",   "opMod_r" },
+    { "eq",      "opEquals" },
+    { "cmp",     "opCmp" },
+    { "iand",    "opAnd" },
+    { "iand_r",  "opAnd_r" },
+    { "ior",     "opOr" },
+    { "ior_r",   "opOr_r" },
+    { "ixor",    "opXor" },
+    { "ixor_r",  "opXor_r" },
+    { "shl",     "opShl" },
+    { "shl_r",   "opShl_r" },
+    { "shr",     "opShr" },
+    { "shr_r",   "opShr_r" },
+    { "ushr",    "opUShr" },
+    { "ushr_r",  "opUShr_r" },
+    { "cat",     "opCat" },
+    { "cat_r",   "opCat_r" },
+    { "assign",  "opAssign" },
+    { "addass",  "opAddAssign" },
+    { "subass",  "opSubAssign" },
+    { "mulass",  "opMulAssign" },
+    { "divass",  "opDivAssign" },
+    { "modass",  "opModAssign" },
+    { "andass",  "opAndAssign" },
+    { "orass",   "opOrAssign" },
+    { "xorass",  "opXorAssign" },
+    { "shlass",  "opShlAssign" },
+    { "shrass",  "opShrAssign" },
+    { "ushrass", "opUShrAssign" },
+    { "catass",  "opCatAssign" },
+    { "postinc", "opPostInc" },
+    { "postdec", "opPostDec" },
+    { "index",   "opIndex" },
+    { "indexass", "opIndexAssign" },
+    { "slice",   "opSlice" },
+    { "sliceass", "opSliceAssign" },
+    { "call",    "opCall" },
+    { "_cast",    "opCast" },
+    { "opIn" },
+    { "opIn_r" },
+    { "opStar" },
+    { "opDot" },
+    { "opDispatch" },
+    { "opDollar" },
+    { "opUnary" },
+    { "opIndexUnary" },
+    { "opSliceUnary" },
+    { "opBinary" },
+    { "opBinaryRight" },
+    { "opOpAssign" },
+    { "opIndexOpAssign" },
+    { "opSliceOpAssign" },
+    { "pow", "opPow" },
+    { "pow_r", "opPow_r" },
+    { "powass", "opPowAssign" },
+
+    { "classNew", "new" },
+    { "classDelete", "delete" },
+
+    // For foreach
+    { "apply", "opApply" },
+    { "applyReverse", "opApplyReverse" },
+
+    // Ranges
+    { "Fempty", "empty" },
+    { "Ffront", "front" },
+    { "Fback", "back" },
+    { "FpopFront", "popFront" },
+    { "FpopBack", "popBack" },
+
+    // For internal functions
+    { "aaLen", "_aaLen" },
+    { "aaKeys", "_aaKeys" },
+    { "aaValues", "_aaValues" },
+    { "aaRehash", "_aaRehash" },
+    { "monitorenter", "_d_monitorenter" },
+    { "monitorexit", "_d_monitorexit" },
+    { "criticalenter", "_d_criticalenter" },
+    { "criticalexit", "_d_criticalexit" },
+    { "_ArrayEq" },
+    { "_ArrayPostblit" },
+    { "_ArrayDtor" },
+
+    // For pragma's
+    { "Pinline", "inline" },
+    { "lib" },
+    { "mangle" },
+    { "msg" },
+    { "startaddress" },
+
+    // For special functions
+    { "tohash", "toHash" },
+    { "tostring", "toString" },
+    { "getmembers", "getMembers" },
+
+    // Special functions
+    { "__alloca", "alloca" },
+    { "main" },
+    { "WinMain" },
+    { "DllMain" },
+    { "tls_get_addr", "___tls_get_addr" },
+    { "entrypoint", "__entrypoint" },
+
+    // varargs implementation
+    { "va_start" },
+
+    // Builtin functions
+    { "std" },
+    { "core" },
+    { "attribute" },
+    { "math" },
+    { "sin" },
+    { "cos" },
+    { "tan" },
+    { "_sqrt", "sqrt" },
+    { "_pow", "pow" },
+    { "atan2" },
+    { "rndtol" },
+    { "expm1" },
+    { "exp2" },
+    { "yl2x" },
+    { "yl2xp1" },
+    { "fabs" },
+    { "bitop" },
+    { "bsf" },
+    { "bsr" },
+    { "bswap" },
+
+    // Traits
+    { "isAbstractClass" },
+    { "isArithmetic" },
+    { "isAssociativeArray" },
+    { "isFinalClass" },
+    { "isTemplate" },
+    { "isPOD" },
+    { "isNested" },
+    { "isFloating" },
+    { "isIntegral" },
+    { "isScalar" },
+    { "isStaticArray" },
+    { "isUnsigned" },
+    { "isVirtualFunction" },
+    { "isVirtualMethod" },
+    { "isAbstractFunction" },
+    { "isFinalFunction" },
+    { "isOverrideFunction" },
+    { "isStaticFunction" },
+    { "isRef" },
+    { "isOut" },
+    { "isLazy" },
+    { "hasMember" },
+    { "identifier" },
+    { "getProtection" },
+    { "parent" },
+    { "getMember" },
+    { "getOverloads" },
+    { "getVirtualFunctions" },
+    { "getVirtualMethods" },
+    { "classInstanceSize" },
+    { "allMembers" },
+    { "derivedMembers" },
+    { "isSame" },
+    { "compiles" },
+    { "parameters" },
+    { "getAliasThis" },
+    { "getAttributes" },
+    { "getFunctionAttributes" },
+    { "getFunctionVariadicStyle" },
+    { "getParameterStorageClasses" },
+    { "getLinkage" },
+    { "getUnitTests" },
+    { "getVirtualIndex" },
+    { "getPointerBitmap" },
+
+    // For C++ mangling
+    { "allocator" },
+    { "basic_string" },
+    { "basic_istream" },
+    { "basic_ostream" },
+    { "basic_iostream" },
+    { "char_traits" },
+
+    // Compiler recognized UDA's
+    { "udaSelector", "selector" },
+};
+
+
+int main()
+{
+    {
+        FILE *fp = fopen("id.h","wb");
+        if (!fp)
+        {
+            printf("can't open id.h\n");
+            exit(EXIT_FAILURE);
+        }
+
+        fprintf(fp, "// File generated by idgen.c\n");
+        fprintf(fp, "#ifndef DMD_ID_H\n");
+        fprintf(fp, "#define DMD_ID_H 1\n");
+        fprintf(fp, "class Identifier;\n");
+        fprintf(fp, "struct Id\n");
+        fprintf(fp, "{\n");
+
+        for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+        {
+            const char *id = msgtable[i].ident;
+            fprintf(fp,"    static Identifier *%s;\n", id);
+        }
+
+        fprintf(fp, "    static void initialize();\n");
+        fprintf(fp, "};\n");
+        fprintf(fp, "#endif\n");
+
+        fclose(fp);
+    }
+
+    {
+        FILE *fp = fopen("id.c","wb");
+        if (!fp)
+        {
+            printf("can't open id.c\n");
+            exit(EXIT_FAILURE);
+        }
+
+        fprintf(fp, "// File generated by idgen.c\n");
+        fprintf(fp, "#include \"identifier.h\"\n");
+        fprintf(fp, "#include \"id.h\"\n");
+
+        for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+        {
+            const char *id = msgtable[i].ident;
+            const char *p = msgtable[i].name;
+
+            if (!p)
+                p = id;
+            fprintf(fp,"Identifier *Id::%s;\n", id);
+        }
+
+        fprintf(fp, "void Id::initialize()\n");
+        fprintf(fp, "{\n");
+
+        for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+        {
+            const char *id = msgtable[i].ident;
+            const char *p = msgtable[i].name;
+
+            if (!p)
+                p = id;
+            fprintf(fp,"    %s = Identifier::idPool(\"%s\");\n", id, p);
+        }
+
+        fprintf(fp, "}\n");
+
+        fclose(fp);
+    }
+
+    {
+        FILE *fp = fopen("id.d","wb");
+        if (!fp)
+        {
+            printf("can't open id.d\n");
+            exit(EXIT_FAILURE);
+        }
+
+        fprintf(fp, "// File generated by idgen.c\n");
+        fprintf(fp, "\n");
+        fprintf(fp, "module ddmd.id;\n");
+        fprintf(fp, "\n");
+        fprintf(fp, "import ddmd.identifier, ddmd.tokens;\n");
+        fprintf(fp, "\n");
+        fprintf(fp, "struct Id\n");
+        fprintf(fp, "{\n");
+
+        for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+        {
+            const char *id = msgtable[i].ident;
+            const char *p = msgtable[i].name;
+
+            if (!p)
+                p = id;
+            fprintf(fp, "    extern (C++) static __gshared Identifier %s;\n", id);
+        }
+
+        fprintf(fp, "\n");
+        fprintf(fp, "    extern (C++) static void initialize()\n");
+        fprintf(fp, "    {\n");
+
+        for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+        {
+            const char *id = msgtable[i].ident;
+            const char *p = msgtable[i].name;
+
+            if (!p)
+                p = id;
+            fprintf(fp,"        %s = Identifier.idPool(\"%s\");\n", id, p);
+        }
+
+        fprintf(fp, "    }\n");
+        fprintf(fp, "}\n");
+
+        fclose(fp);
+    }
+
+    return EXIT_SUCCESS;
+}
diff --git a/gcc/d/dfrontend/impcnvgen.c b/gcc/d/dfrontend/impcnvgen.c
new file mode 100644
index 00000000000..2444207583f
--- /dev/null
+++ b/gcc/d/dfrontend/impcnvgen.c
@@ -0,0 +1,600 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/impcnvgen.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mtype.h"
+
+TY impcnvResultTab[TMAX][TMAX];
+TY impcnvType1Tab[TMAX][TMAX];
+TY impcnvType2Tab[TMAX][TMAX];
+int impcnvWarnTab[TMAX][TMAX];
+
+int integral_promotion(int t)
+{
+    switch (t)
+    {
+        case Tchar:
+        case Twchar:
+        case Tbool:
+        case Tint8:
+        case Tuns8:
+        case Tint16:
+        case Tuns16:    return Tint32;
+        case Tdchar:    return Tuns32;
+        default:        return t;
+    }
+}
+
+void init()
+{   int i, j;
+
+    // Set conversion tables
+    for (i = 0; i < TMAX; i++)
+        for (j = 0; j < TMAX; j++)
+        {   impcnvResultTab[i][j] = Terror;
+            impcnvType1Tab[i][j] = Terror;
+            impcnvType2Tab[i][j] = Terror;
+            impcnvWarnTab[i][j] = 0;
+        }
+
+#define X(t1,t2, nt1,nt2, rt)           \
+        impcnvResultTab[t1][t2] = rt;      \
+        impcnvType1Tab[t1][t2] = nt1;      \
+        impcnvType2Tab[t1][t2] = nt2;
+
+
+    /* ======================= */
+
+    X(Tbool,Tbool,   Tbool,Tbool,    Tbool)
+    X(Tbool,Tint8,   Tint32,Tint32,  Tint32)
+    X(Tbool,Tuns8,   Tint32,Tint32,  Tint32)
+    X(Tbool,Tint16,  Tint32,Tint32,  Tint32)
+    X(Tbool,Tuns16,  Tint32,Tint32,  Tint32)
+    X(Tbool,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tbool,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tbool,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tbool,Tuns64,  Tuns64,Tuns64,  Tuns64)
+    X(Tbool,Tint128, Tint128,Tint128, Tint128)
+    X(Tbool,Tuns128, Tuns128,Tuns128, Tuns128)
+
+    X(Tbool,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tbool,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tbool,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tbool,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tbool,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tbool,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tbool,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tbool,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tbool,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tint8,Tint8,   Tint32,Tint32,  Tint32)
+    X(Tint8,Tuns8,   Tint32,Tint32,  Tint32)
+    X(Tint8,Tint16,  Tint32,Tint32,  Tint32)
+    X(Tint8,Tuns16,  Tint32,Tint32,  Tint32)
+    X(Tint8,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tint8,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tint8,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tint8,Tuns64,  Tuns64,Tuns64,  Tuns64)
+    X(Tint8,Tint128, Tint128,Tint128, Tint128)
+    X(Tint8,Tuns128, Tuns128,Tuns128, Tuns128)
+
+    X(Tint8,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tint8,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tint8,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tint8,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tint8,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tint8,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tint8,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tint8,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tint8,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tuns8,Tuns8,   Tint32,Tint32,  Tint32)
+    X(Tuns8,Tint16,  Tint32,Tint32,  Tint32)
+    X(Tuns8,Tuns16,  Tint32,Tint32,  Tint32)
+    X(Tuns8,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tuns8,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tuns8,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tuns8,Tuns64,  Tuns64,Tuns64,  Tuns64)
+    X(Tuns8,Tint128,  Tint128,Tint128,  Tint128)
+    X(Tuns8,Tuns128,  Tuns128,Tuns128,  Tuns128)
+
+    X(Tuns8,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tuns8,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tuns8,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tuns8,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tuns8,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tuns8,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tuns8,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tuns8,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tuns8,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tint16,Tint16,  Tint32,Tint32,  Tint32)
+    X(Tint16,Tuns16,  Tint32,Tint32,  Tint32)
+    X(Tint16,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tint16,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tint16,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tint16,Tuns64,  Tuns64,Tuns64,  Tuns64)
+    X(Tint16,Tint128,  Tint128,Tint128,  Tint128)
+    X(Tint16,Tuns128,  Tuns128,Tuns128,  Tuns128)
+
+    X(Tint16,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tint16,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tint16,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tint16,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tint16,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tint16,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tint16,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tint16,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tint16,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tuns16,Tuns16,  Tint32,Tint32,  Tint32)
+    X(Tuns16,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tuns16,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tuns16,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tuns16,Tuns64,  Tuns64,Tuns64,  Tuns64)
+    X(Tuns16,Tint128, Tint128,Tint128,  Tint128)
+    X(Tuns16,Tuns128, Tuns128,Tuns128,  Tuns128)
+
+    X(Tuns16,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tuns16,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tuns16,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tuns16,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tuns16,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tuns16,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tuns16,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tuns16,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tuns16,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tint32,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tint32,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tint32,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tint32,Tuns64,  Tuns64,Tuns64,  Tuns64)
+    X(Tint32,Tint128, Tint128,Tint128,  Tint128)
+    X(Tint32,Tuns128, Tuns128,Tuns128,  Tuns128)
+
+    X(Tint32,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tint32,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tint32,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tint32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tint32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tint32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tint32,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tint32,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tint32,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tuns32,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tuns32,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tuns32,Tuns64,  Tuns64,Tuns64,  Tuns64)
+    X(Tuns32,Tint128,  Tint128,Tint128,  Tint128)
+    X(Tuns32,Tuns128,  Tuns128,Tuns128,  Tuns128)
+
+    X(Tuns32,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tuns32,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tuns32,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tuns32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tuns32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tuns32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tuns32,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tuns32,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tuns32,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tint64,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tint64,Tuns64,  Tuns64,Tuns64,  Tuns64)
+    X(Tint64,Tint128,  Tint128,Tint128,  Tint128)
+    X(Tint64,Tuns128,  Tuns128,Tuns128,  Tuns128)
+
+    X(Tint64,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tint64,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tint64,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tint64,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tint64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tint64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tint64,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tint64,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tint64,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tuns64,Tuns64,  Tuns64,Tuns64,  Tuns64)
+    X(Tuns64,Tint128,  Tint128,Tint128,  Tint128)
+    X(Tuns64,Tuns128,  Tuns128,Tuns128,  Tuns128)
+
+    X(Tuns64,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tuns64,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tuns64,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tuns64,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tuns64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tuns64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tuns64,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tuns64,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tuns64,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tint128,Tint128,  Tint128,Tint128,  Tint128)
+    X(Tint128,Tuns128,  Tuns128,Tuns128,  Tuns128)
+
+    X(Tint128,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tint128,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tint128,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tint128,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tint128,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tint128,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tint128,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tint128,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tint128,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tuns128,Tuns128,  Tuns128,Tuns128,  Tuns128)
+
+    X(Tuns128,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tuns128,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tuns128,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tuns128,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tuns128,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tuns128,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tuns128,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tuns128,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tuns128,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tfloat32,Tfloat32,  Tfloat32,Tfloat32, Tfloat32)
+    X(Tfloat32,Tfloat64,  Tfloat64,Tfloat64, Tfloat64)
+    X(Tfloat32,Tfloat80,  Tfloat80,Tfloat80, Tfloat80)
+
+    X(Tfloat32,Timaginary32,  Tfloat32,Timaginary32, Tfloat32)
+    X(Tfloat32,Timaginary64,  Tfloat64,Timaginary64, Tfloat64)
+    X(Tfloat32,Timaginary80,  Tfloat80,Timaginary80, Tfloat80)
+
+    X(Tfloat32,Tcomplex32,  Tfloat32,Tcomplex32, Tcomplex32)
+    X(Tfloat32,Tcomplex64,  Tfloat64,Tcomplex64, Tcomplex64)
+    X(Tfloat32,Tcomplex80,  Tfloat80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Tfloat64,Tfloat64,  Tfloat64,Tfloat64, Tfloat64)
+    X(Tfloat64,Tfloat80,  Tfloat80,Tfloat80, Tfloat80)
+
+    X(Tfloat64,Timaginary32,  Tfloat64,Timaginary64, Tfloat64)
+    X(Tfloat64,Timaginary64,  Tfloat64,Timaginary64, Tfloat64)
+    X(Tfloat64,Timaginary80,  Tfloat80,Timaginary80, Tfloat80)
+
+    X(Tfloat64,Tcomplex32,  Tfloat64,Tcomplex64, Tcomplex64)
+    X(Tfloat64,Tcomplex64,  Tfloat64,Tcomplex64, Tcomplex64)
+    X(Tfloat64,Tcomplex80,  Tfloat80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Tfloat80,Tfloat80,  Tfloat80,Tfloat80, Tfloat80)
+
+    X(Tfloat80,Timaginary32,  Tfloat80,Timaginary80, Tfloat80)
+    X(Tfloat80,Timaginary64,  Tfloat80,Timaginary80, Tfloat80)
+    X(Tfloat80,Timaginary80,  Tfloat80,Timaginary80, Tfloat80)
+
+    X(Tfloat80,Tcomplex32,  Tfloat80,Tcomplex80, Tcomplex80)
+    X(Tfloat80,Tcomplex64,  Tfloat80,Tcomplex80, Tcomplex80)
+    X(Tfloat80,Tcomplex80,  Tfloat80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Timaginary32,Timaginary32,  Timaginary32,Timaginary32, Timaginary32)
+    X(Timaginary32,Timaginary64,  Timaginary64,Timaginary64, Timaginary64)
+    X(Timaginary32,Timaginary80,  Timaginary80,Timaginary80, Timaginary80)
+
+    X(Timaginary32,Tcomplex32,  Timaginary32,Tcomplex32, Tcomplex32)
+    X(Timaginary32,Tcomplex64,  Timaginary64,Tcomplex64, Tcomplex64)
+    X(Timaginary32,Tcomplex80,  Timaginary80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Timaginary64,Timaginary64,  Timaginary64,Timaginary64, Timaginary64)
+    X(Timaginary64,Timaginary80,  Timaginary80,Timaginary80, Timaginary80)
+
+    X(Timaginary64,Tcomplex32,  Timaginary64,Tcomplex64, Tcomplex64)
+    X(Timaginary64,Tcomplex64,  Timaginary64,Tcomplex64, Tcomplex64)
+    X(Timaginary64,Tcomplex80,  Timaginary80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Timaginary80,Timaginary80,  Timaginary80,Timaginary80, Timaginary80)
+
+    X(Timaginary80,Tcomplex32,  Timaginary80,Tcomplex80, Tcomplex80)
+    X(Timaginary80,Tcomplex64,  Timaginary80,Tcomplex80, Tcomplex80)
+    X(Timaginary80,Tcomplex80,  Timaginary80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Tcomplex32,Tcomplex32,  Tcomplex32,Tcomplex32, Tcomplex32)
+    X(Tcomplex32,Tcomplex64,  Tcomplex64,Tcomplex64, Tcomplex64)
+    X(Tcomplex32,Tcomplex80,  Tcomplex80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Tcomplex64,Tcomplex64,  Tcomplex64,Tcomplex64, Tcomplex64)
+    X(Tcomplex64,Tcomplex80,  Tcomplex80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Tcomplex80,Tcomplex80,  Tcomplex80,Tcomplex80, Tcomplex80)
+
+#undef X
+
+#define Y(t1,t2)        impcnvWarnTab[t1][t2] = 1;
+
+    Y(Tuns8, Tint8)
+    Y(Tint16, Tint8)
+    Y(Tuns16, Tint8)
+    Y(Tint32, Tint8)
+    Y(Tuns32, Tint8)
+    Y(Tint64, Tint8)
+    Y(Tuns64, Tint8)
+    Y(Tint128, Tint8)
+    Y(Tuns128, Tint8)
+
+    Y(Tint8, Tuns8)
+    Y(Tint16, Tuns8)
+    Y(Tuns16, Tuns8)
+    Y(Tint32, Tuns8)
+    Y(Tuns32, Tuns8)
+    Y(Tint64, Tuns8)
+    Y(Tuns64, Tuns8)
+    Y(Tint128, Tuns8)
+    Y(Tuns128, Tuns8)
+
+    Y(Tint8, Tchar)
+    Y(Tint16, Tchar)
+    Y(Tuns16, Tchar)
+    Y(Tint32, Tchar)
+    Y(Tuns32, Tchar)
+    Y(Tint64, Tchar)
+    Y(Tuns64, Tchar)
+    Y(Tint128, Tchar)
+    Y(Tuns128, Tchar)
+
+    Y(Tuns16, Tint16)
+    Y(Tint32, Tint16)
+    Y(Tuns32, Tint16)
+    Y(Tint64, Tint16)
+    Y(Tuns64, Tint16)
+    Y(Tint128, Tint16)
+    Y(Tuns128, Tint16)
+
+    Y(Tint16, Tuns16)
+    Y(Tint32, Tuns16)
+    Y(Tuns32, Tuns16)
+    Y(Tint64, Tuns16)
+    Y(Tuns64, Tuns16)
+    Y(Tint128, Tuns16)
+    Y(Tuns128, Tuns16)
+
+    Y(Tint16, Twchar)
+    Y(Tint32, Twchar)
+    Y(Tuns32, Twchar)
+    Y(Tint64, Twchar)
+    Y(Tuns64, Twchar)
+    Y(Tint128, Twchar)
+    Y(Tuns128, Twchar)
+
+//    Y(Tuns32, Tint32)
+    Y(Tint64, Tint32)
+    Y(Tuns64, Tint32)
+    Y(Tint128, Tint32)
+    Y(Tuns128, Tint32)
+
+//    Y(Tint32, Tuns32)
+    Y(Tint64, Tuns32)
+    Y(Tuns64, Tuns32)
+    Y(Tint128, Tuns32)
+    Y(Tuns128, Tuns32)
+
+    Y(Tint64, Tdchar)
+    Y(Tuns64, Tdchar)
+    Y(Tint128, Tdchar)
+    Y(Tuns128, Tdchar)
+
+//    Y(Tint64, Tuns64)
+//    Y(Tuns64, Tint64)
+    Y(Tint128, Tint64)
+    Y(Tuns128, Tint64)
+    Y(Tint128, Tuns64)
+    Y(Tuns128, Tuns64)
+
+//    Y(Tint128, Tuns128)
+//    Y(Tuns128, Tint128)
+
+    for (i = 0; i < TMAX; i++)
+        for (j = 0; j < TMAX; j++)
+        {
+            if (impcnvResultTab[i][j] == Terror)
+            {
+                impcnvResultTab[i][j] = impcnvResultTab[j][i];
+                impcnvType1Tab[i][j] = impcnvType2Tab[j][i];
+                impcnvType2Tab[i][j] = impcnvType1Tab[j][i];
+            }
+        }
+}
+
+int main()
+{
+    int i;
+    int j;
+
+    init();
+
+    {
+        FILE *fp = fopen("impcnvtab.c","wb");
+
+        fprintf(fp,"// This file is generated by impcnvgen.c\n");
+        fprintf(fp,"#include \"mtype.h\"\n");
+
+        fprintf(fp,"unsigned char impcnvResult[TMAX][TMAX] =\n{\n");
+        for (i = 0; i < TMAX; i++)
+        {
+            if (i)
+                fprintf(fp, ",");
+            fprintf(fp, "{");
+            for (j = 0; j < TMAX; j++)
+            {
+                if (j)
+                    fprintf(fp, ",");
+                fprintf(fp, "%d",impcnvResultTab[i][j]);
+            }
+            fprintf(fp, "}\n");
+        }
+        fprintf(fp,"};\n");
+
+        fprintf(fp,"unsigned char impcnvType1[TMAX][TMAX] =\n{\n");
+        for (i = 0; i < TMAX; i++)
+        {
+            if (i)
+                fprintf(fp, ",");
+            fprintf(fp, "{");
+            for (j = 0; j < TMAX; j++)
+            {
+                if (j)
+                    fprintf(fp, ",");
+                fprintf(fp, "%d",impcnvType1Tab[i][j]);
+            }
+            fprintf(fp, "}\n");
+        }
+        fprintf(fp,"};\n");
+
+        fprintf(fp,"unsigned char impcnvType2[TMAX][TMAX] =\n{\n");
+        for (i = 0; i < TMAX; i++)
+        {
+            if (i)
+                fprintf(fp, ",");
+            fprintf(fp, "{");
+            for (j = 0; j < TMAX; j++)
+            {
+                if (j)
+                    fprintf(fp, ",");
+                fprintf(fp, "%d",impcnvType2Tab[i][j]);
+            }
+            fprintf(fp, "}\n");
+        }
+        fprintf(fp,"};\n");
+
+        fprintf(fp,"unsigned char impcnvWarn[TMAX][TMAX] =\n{\n");
+        for (i = 0; i < TMAX; i++)
+        {
+            if (i)
+                fprintf(fp, ",");
+            fprintf(fp, "{");
+            for (j = 0; j < TMAX; j++)
+            {
+                if (j)
+                    fprintf(fp, ",");
+                fprintf(fp, "%d",impcnvWarnTab[i][j]);
+            }
+            fprintf(fp, "}\n");
+        }
+        fprintf(fp,"};\n");
+
+        fclose(fp);
+    }
+
+    {
+        FILE *fp = fopen("impcnvtab.d", "wb");
+
+        fprintf(fp, "// This file is generated by impcnvgen.c\n");
+        fprintf(fp, "module ddmd.impcnvtab;\n");
+        fprintf(fp, "\n");
+        fprintf(fp, "import ddmd.mtype;\n");
+        fprintf(fp, "\n");
+
+        fprintf(fp, "extern (C++) __gshared ubyte[TMAX][TMAX] impcnvResult =\n[\n");
+        for (i = 0; i < TMAX; i++)
+        {
+            if (i)
+                fprintf(fp, ",\n");
+            fprintf(fp, "    [");
+            for (j = 0; j < TMAX; j++)
+            {
+                if (j)
+                    fprintf(fp, ",");
+                fprintf(fp, "%d", impcnvResultTab[i][j]);
+            }
+            fprintf(fp, "]");
+        }
+        fprintf(fp, "\n];\n");
+
+        fprintf(fp, "extern (C++) __gshared ubyte[TMAX][TMAX] impcnvType1 =\n[\n");
+        for (i = 0; i < TMAX; i++)
+        {
+            if (i)
+                fprintf(fp, ",\n");
+            fprintf(fp, "    [");
+            for (j = 0; j < TMAX; j++)
+            {
+                if (j)
+                    fprintf(fp, ",");
+                fprintf(fp, "%d", impcnvType1Tab[i][j]);
+            }
+            fprintf(fp, "]");
+        }
+        fprintf(fp, "\n];\n");
+
+        fprintf(fp, "extern (C++) __gshared ubyte[TMAX][TMAX] impcnvType2 =\n[\n");
+        for (i = 0; i < TMAX; i++)
+        {
+            if (i)
+                fprintf(fp, ",\n");
+            fprintf(fp, "    [");
+            for (j = 0; j < TMAX; j++)
+            {
+                if (j)
+                    fprintf(fp, ",");
+                fprintf(fp, "%d",impcnvType2Tab[i][j]);
+            }
+            fprintf(fp, "]");
+        }
+        fprintf(fp,"\n];\n");
+
+        fprintf(fp,"extern (C++) __gshared ubyte[TMAX][TMAX] impcnvWarn =\n[\n");
+        for (i = 0; i < TMAX; i++)
+        {
+            if (i)
+                fprintf(fp, ",\n");
+            fprintf(fp, "    [");
+            for (j = 0; j < TMAX; j++)
+            {
+                if (j)
+                    fprintf(fp, ",");
+                fprintf(fp, "%d", impcnvWarnTab[i][j]);
+            }
+            fprintf(fp, "]");
+        }
+        fprintf(fp, "\n];\n");
+
+        fclose(fp);
+    }
+
+    return EXIT_SUCCESS;
+}
diff --git a/gcc/d/dfrontend/imphint.c b/gcc/d/dfrontend/imphint.c
new file mode 100644
index 00000000000..d9963a3af8b
--- /dev/null
+++ b/gcc/d/dfrontend/imphint.c
@@ -0,0 +1,73 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 2010-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/imphint.c
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>
+
+#include "mars.h"
+
+/******************************************
+ * Looks for undefined identifier s to see
+ * if it might be undefined because an import
+ * was not specified.
+ * Not meant to be a comprehensive list of names in each module,
+ * just the most common ones.
+ */
+
+const char *importHint(const char *s)
+{
+    static const char *modules[] =
+    {   "core.stdc.stdio",
+        "std.stdio",
+        "std.math",
+        NULL
+    };
+    static const char *names[] =
+    {
+        "printf", NULL,
+        "writeln", NULL,
+        "sin", "cos", "sqrt", "fabs", NULL,
+    };
+    int m = 0;
+    for (int n = 0; modules[m]; n++)
+    {
+        const char *p = names[n];
+        if (p == NULL)
+        {
+            m++;
+            continue;
+        }
+        assert(modules[m]);
+        if (strcmp(s, p) == 0)
+            return modules[m];
+    }
+    return NULL;        // didn't find it
+}
+
+#if UNITTEST
+
+void unittest_importHint()
+{
+    const char *p;
+
+    p = importHint("printf");
+    assert(p);
+    p = importHint("fabs");
+    assert(p);
+    p = importHint("xxxxx");
+    assert(!p);
+}
+
+#endif
diff --git a/gcc/d/dfrontend/import.h b/gcc/d/dfrontend/import.h
new file mode 100644
index 00000000000..3b59d1f85f6
--- /dev/null
+++ b/gcc/d/dfrontend/import.h
@@ -0,0 +1,69 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/import.h
+ */
+
+#ifndef DMD_IMPORT_H
+#define DMD_IMPORT_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+
+
+class Identifier;
+struct Scope;
+class Module;
+class Package;
+class AliasDeclaration;
+
+class Import : public Dsymbol
+{
+public:
+    /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2;
+     */
+
+    Identifiers *packages;      // array of Identifier's representing packages
+    Identifier *id;             // module Identifier
+    Identifier *aliasId;
+    int isstatic;               // !=0 if static import
+    Prot protection;
+
+    // Pairs of alias=name to bind into current namespace
+    Identifiers names;
+    Identifiers aliases;
+
+    Module *mod;
+    Package *pkg;               // leftmost package/module
+
+    AliasDeclarations aliasdecls; // corresponding AliasDeclarations for alias=name pairs
+
+    Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId,
+        int isstatic);
+    void addAlias(Identifier *name, Identifier *alias);
+    const char *kind();
+    Prot prot();
+    Dsymbol *syntaxCopy(Dsymbol *s);    // copy only syntax trees
+    void load(Scope *sc);
+    void importAll(Scope *sc);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    Dsymbol *toAlias();
+    void addMember(Scope *sc, ScopeDsymbol *sds);
+    void setScope(Scope* sc);
+    Dsymbol *search(Loc loc, Identifier *ident, int flags = SearchLocalsOnly);
+    bool overloadInsert(Dsymbol *s);
+
+    Import *isImport() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#endif /* DMD_IMPORT_H */
diff --git a/gcc/d/dfrontend/init.c b/gcc/d/dfrontend/init.c
new file mode 100644
index 00000000000..0e9f5019abc
--- /dev/null
+++ b/gcc/d/dfrontend/init.c
@@ -0,0 +1,288 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/init.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "checkedint.h"
+#include "mars.h"
+#include "init.h"
+#include "expression.h"
+#include "statement.h"
+#include "identifier.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "mtype.h"
+#include "hdrgen.h"
+#include "template.h"
+#include "id.h"
+#include "tokens.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+Expression *initializerToExpression(Initializer *i, Type *t = NULL);
+Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
+
+/********************************** Initializer *******************************/
+
+Initializer::Initializer(Loc loc)
+{
+    this->loc = loc;
+}
+
+Initializers *Initializer::arraySyntaxCopy(Initializers *ai)
+{
+    Initializers *a = NULL;
+    if (ai)
+    {
+        a = new Initializers();
+        a->setDim(ai->dim);
+        for (size_t i = 0; i < a->dim; i++)
+            (*a)[i] = (*ai)[i]->syntaxCopy();
+    }
+    return a;
+}
+
+const char *Initializer::toChars()
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+    ::toCBuffer(this, &buf, &hgs);
+    return buf.extractString();
+}
+
+/********************************** ErrorInitializer ***************************/
+
+ErrorInitializer::ErrorInitializer()
+    : Initializer(Loc())
+{
+}
+
+Initializer *ErrorInitializer::syntaxCopy()
+{
+    return this;
+}
+
+/********************************** VoidInitializer ***************************/
+
+VoidInitializer::VoidInitializer(Loc loc)
+    : Initializer(loc)
+{
+    type = NULL;
+}
+
+Initializer *VoidInitializer::syntaxCopy()
+{
+    return new VoidInitializer(loc);
+}
+
+/********************************** StructInitializer *************************/
+
+StructInitializer::StructInitializer(Loc loc)
+    : Initializer(loc)
+{
+}
+
+Initializer *StructInitializer::syntaxCopy()
+{
+    StructInitializer *ai = new StructInitializer(loc);
+    assert(field.dim == value.dim);
+    ai->field.setDim(field.dim);
+    ai->value.setDim(value.dim);
+    for (size_t i = 0; i < field.dim; i++)
+    {
+        ai->field[i] = field[i];
+        ai->value[i] = value[i]->syntaxCopy();
+    }
+    return ai;
+}
+
+void StructInitializer::addInit(Identifier *field, Initializer *value)
+{
+    //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
+    this->field.push(field);
+    this->value.push(value);
+}
+
+/********************************** ArrayInitializer ************************************/
+
+ArrayInitializer::ArrayInitializer(Loc loc)
+    : Initializer(loc)
+{
+    dim = 0;
+    type = NULL;
+    sem = false;
+}
+
+Initializer *ArrayInitializer::syntaxCopy()
+{
+    //printf("ArrayInitializer::syntaxCopy()\n");
+    ArrayInitializer *ai = new ArrayInitializer(loc);
+    assert(index.dim == value.dim);
+    ai->index.setDim(index.dim);
+    ai->value.setDim(value.dim);
+    for (size_t i = 0; i < ai->value.dim; i++)
+    {
+        ai->index[i] = index[i] ? index[i]->syntaxCopy() : NULL;
+        ai->value[i] = value[i]->syntaxCopy();
+    }
+    return ai;
+}
+
+void ArrayInitializer::addInit(Expression *index, Initializer *value)
+{
+    this->index.push(index);
+    this->value.push(value);
+    dim = 0;
+    type = NULL;
+}
+
+bool ArrayInitializer::isAssociativeArray()
+{
+    for (size_t i = 0; i < value.dim; i++)
+    {
+        if (index[i])
+            return true;
+    }
+    return false;
+}
+
+/********************************
+ * If possible, convert array initializer to associative array initializer.
+ */
+
+Expression *ArrayInitializer::toAssocArrayLiteral()
+{
+    Expression *e;
+
+    //printf("ArrayInitializer::toAssocArrayInitializer()\n");
+    //static int i; if (++i == 2) halt();
+    Expressions *keys = new Expressions();
+    keys->setDim(value.dim);
+    Expressions *values = new Expressions();
+    values->setDim(value.dim);
+
+    for (size_t i = 0; i < value.dim; i++)
+    {
+        e = index[i];
+        if (!e)
+            goto Lno;
+        (*keys)[i] = e;
+
+        Initializer *iz = value[i];
+        if (!iz)
+            goto Lno;
+        e = initializerToExpression(iz);
+        if (!e)
+            goto Lno;
+        (*values)[i] = e;
+    }
+    e = new AssocArrayLiteralExp(loc, keys, values);
+    return e;
+
+Lno:
+    delete keys;
+    delete values;
+    error(loc, "not an associative array initializer");
+    return new ErrorExp();
+}
+
+/********************************** ExpInitializer ************************************/
+
+ExpInitializer::ExpInitializer(Loc loc, Expression *exp)
+    : Initializer(loc)
+{
+    this->exp = exp;
+    this->expandTuples = false;
+}
+
+Initializer *ExpInitializer::syntaxCopy()
+{
+    return new ExpInitializer(loc, exp->syntaxCopy());
+}
+
+#if 1   // should be removed and rely on ctfeInterpreter()
+bool arrayHasNonConstPointers(Expressions *elems);
+
+bool hasNonConstPointers(Expression *e)
+{
+    if (e->type->ty == Terror)
+        return false;
+
+    if (e->op == TOKnull)
+        return false;
+    if (e->op == TOKstructliteral)
+    {
+        StructLiteralExp *se = (StructLiteralExp *)e;
+        return arrayHasNonConstPointers(se->elements);
+    }
+    if (e->op == TOKarrayliteral)
+    {
+        if (!e->type->nextOf()->hasPointers())
+            return false;
+        ArrayLiteralExp *ae = (ArrayLiteralExp *)e;
+        return arrayHasNonConstPointers(ae->elements);
+    }
+    if (e->op == TOKassocarrayliteral)
+    {
+        AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
+        if (ae->type->nextOf()->hasPointers() &&
+            arrayHasNonConstPointers(ae->values))
+                return true;
+        if (((TypeAArray *)ae->type)->index->hasPointers())
+            return arrayHasNonConstPointers(ae->keys);
+        return false;
+    }
+    if(e->op == TOKaddress)
+    {
+        AddrExp *ae = (AddrExp *)e;
+        if (ae->e1->op == TOKstructliteral)
+        {
+            StructLiteralExp *se = (StructLiteralExp *)ae->e1;
+            if (!(se->stageflags & stageSearchPointers))
+            {
+                int old = se->stageflags;
+                se->stageflags |= stageSearchPointers;
+                bool ret = arrayHasNonConstPointers(se->elements);
+                se->stageflags = old;
+                return ret;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+    if (e->type->ty== Tpointer && e->type->nextOf()->ty != Tfunction)
+    {
+        if (e->op == TOKsymoff) // address of a global is OK
+            return false;
+        if (e->op == TOKint64)  // cast(void *)int is OK
+            return false;
+        if (e->op == TOKstring) // "abc".ptr is OK
+            return false;
+        return true;
+    }
+    return false;
+}
+
+bool arrayHasNonConstPointers(Expressions *elems)
+{
+    for (size_t i = 0; i < elems->dim; i++)
+    {
+        Expression *e = (*elems)[i];
+        if (e && hasNonConstPointers(e))
+            return true;
+    }
+    return false;
+}
+#endif
diff --git a/gcc/d/dfrontend/init.h b/gcc/d/dfrontend/init.h
new file mode 100644
index 00000000000..ef8ae073666
--- /dev/null
+++ b/gcc/d/dfrontend/init.h
@@ -0,0 +1,121 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/init.h
+ */
+
+#ifndef INIT_H
+#define INIT_H
+
+#include "root.h"
+
+#include "mars.h"
+#include "arraytypes.h"
+#include "visitor.h"
+
+class Identifier;
+class Expression;
+struct Scope;
+class Type;
+class AggregateDeclaration;
+class ErrorInitializer;
+class VoidInitializer;
+class StructInitializer;
+class ArrayInitializer;
+class ExpInitializer;
+
+enum NeedInterpret { INITnointerpret, INITinterpret };
+
+class Initializer : public RootObject
+{
+public:
+    Loc loc;
+
+    Initializer(Loc loc);
+    virtual Initializer *syntaxCopy() = 0;
+    static Initializers *arraySyntaxCopy(Initializers *ai);
+
+    const char *toChars();
+
+    virtual ErrorInitializer   *isErrorInitializer() { return NULL; }
+    virtual VoidInitializer    *isVoidInitializer() { return NULL; }
+    virtual StructInitializer  *isStructInitializer()  { return NULL; }
+    virtual ArrayInitializer   *isArrayInitializer()  { return NULL; }
+    virtual ExpInitializer     *isExpInitializer()  { return NULL; }
+    virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+class VoidInitializer : public Initializer
+{
+public:
+    Type *type;         // type that this will initialize to
+
+    VoidInitializer(Loc loc);
+    Initializer *syntaxCopy();
+
+    virtual VoidInitializer *isVoidInitializer() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ErrorInitializer : public Initializer
+{
+public:
+    ErrorInitializer();
+    Initializer *syntaxCopy();
+
+    virtual ErrorInitializer *isErrorInitializer() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class StructInitializer : public Initializer
+{
+public:
+    Identifiers field;  // of Identifier *'s
+    Initializers value; // parallel array of Initializer *'s
+
+    StructInitializer(Loc loc);
+    Initializer *syntaxCopy();
+    void addInit(Identifier *field, Initializer *value);
+
+    StructInitializer *isStructInitializer() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ArrayInitializer : public Initializer
+{
+public:
+    Expressions index;  // indices
+    Initializers value; // of Initializer *'s
+    unsigned dim;       // length of array being initialized
+    Type *type;         // type that array will be used to initialize
+    bool sem;           // true if semantic() is run
+
+    ArrayInitializer(Loc loc);
+    Initializer *syntaxCopy();
+    void addInit(Expression *index, Initializer *value);
+    bool isAssociativeArray();
+    Expression *toAssocArrayLiteral();
+
+    ArrayInitializer *isArrayInitializer() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ExpInitializer : public Initializer
+{
+public:
+    Expression *exp;
+    bool expandTuples;
+
+    ExpInitializer(Loc loc, Expression *exp);
+    Initializer *syntaxCopy();
+
+    virtual ExpInitializer *isExpInitializer() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#endif
diff --git a/gcc/d/dfrontend/initsem.c b/gcc/d/dfrontend/initsem.c
new file mode 100644
index 00000000000..864c12406e1
--- /dev/null
+++ b/gcc/d/dfrontend/initsem.c
@@ -0,0 +1,922 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2017 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+#include "checkedint.h"
+#include "init.h"
+#include "expression.h"
+#include "statement.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "mtype.h"
+#include "template.h"
+#include "id.h"
+
+FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *initializerToExpression(Initializer *i, Type *t = NULL);
+Initializer *inferType(Initializer *init, Scope *sc);
+Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
+bool hasNonConstPointers(Expression *e);
+
+class InitializerSemanticVisitor : public Visitor
+{
+public:
+    Initializer *result;
+    Scope *sc;
+    Type *t;
+    NeedInterpret needInterpret;
+
+    InitializerSemanticVisitor(Scope *sc, Type *t, NeedInterpret needInterpret)
+    {
+        this->result = NULL;
+        this->sc = sc;
+        this->t = t;
+        this->needInterpret = needInterpret;
+    }
+
+    void visit(ErrorInitializer *i)
+    {
+        //printf("ErrorInitializer::semantic(t = %p)\n", t);
+        result = i;
+    }
+
+    void visit(VoidInitializer *i)
+    {
+        //printf("VoidInitializer::semantic(t = %p)\n", t);
+        i->type = t;
+        result = i;
+    }
+
+    void visit(StructInitializer *i)
+    {
+        //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars());
+        t = t->toBasetype();
+        if (t->ty == Tsarray && t->nextOf()->toBasetype()->ty == Tstruct)
+            t = t->nextOf()->toBasetype();
+        if (t->ty == Tstruct)
+        {
+            StructDeclaration *sd = ((TypeStruct *)t)->sym;
+            if (sd->ctor)
+            {
+                error(i->loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead",
+                      sd->kind(), sd->toChars(), sd->toChars());
+                result = new ErrorInitializer();
+                return;
+            }
+            sd->size(i->loc);
+            if (sd->sizeok != SIZEOKdone)
+            {
+                result = new ErrorInitializer();
+                return;
+            }
+            size_t nfields = sd->fields.dim - sd->isNested();
+
+            //expandTuples for non-identity arguments?
+
+            Expressions *elements = new Expressions();
+            elements->setDim(nfields);
+            for (size_t j = 0; j < elements->dim; j++)
+                (*elements)[j] = NULL;
+
+            // Run semantic for explicitly given initializers
+            // TODO: this part is slightly different from StructLiteralExp::semantic.
+            bool errors = false;
+            for (size_t fieldi = 0, j = 0; j < i->field.dim; j++)
+            {
+                if (Identifier *id = i->field[j])
+                {
+                    Dsymbol *s = sd->search(i->loc, id);
+                    if (!s)
+                    {
+                        s = sd->search_correct(id);
+                        if (s)
+                            error(i->loc, "'%s' is not a member of '%s', did you mean %s '%s'?",
+                                  id->toChars(), sd->toChars(), s->kind(), s->toChars());
+                        else
+                            error(i->loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars());
+                        result = new ErrorInitializer();
+                        return;
+                    }
+                    s = s->toAlias();
+
+                    // Find out which field index it is
+                    for (fieldi = 0; 1; fieldi++)
+                    {
+                        if (fieldi >= nfields)
+                        {
+                            error(i->loc, "%s.%s is not a per-instance initializable field",
+                                  sd->toChars(), s->toChars());
+                            result = new ErrorInitializer();
+                            return;
+                        }
+                        if (s == sd->fields[fieldi])
+                            break;
+                    }
+                }
+                else if (fieldi >= nfields)
+                {
+                    error(i->loc, "too many initializers for %s", sd->toChars());
+                    result = new ErrorInitializer();
+                    return;
+                }
+
+                VarDeclaration *vd = sd->fields[fieldi];
+                if ((*elements)[fieldi])
+                {
+                    error(i->loc, "duplicate initializer for field '%s'", vd->toChars());
+                    errors = true;
+                    continue;
+                }
+                for (size_t j = 0; j < nfields; j++)
+                {
+                    VarDeclaration *v2 = sd->fields[j];
+                    bool overlap = (vd->offset < v2->offset + v2->type->size() &&
+                                    v2->offset < vd->offset + vd->type->size());
+                    if (overlap && (*elements)[j])
+                    {
+                        error(i->loc, "overlapping initialization for field %s and %s",
+                              v2->toChars(), vd->toChars());
+                        errors = true;
+                        continue;
+                    }
+                }
+
+                assert(sc);
+                Initializer *iz = i->value[j];
+                iz = ::semantic(iz, sc, vd->type->addMod(t->mod), needInterpret);
+                Expression *ex = initializerToExpression(iz);
+                if (ex->op == TOKerror)
+                {
+                    errors = true;
+                    continue;
+                }
+                i->value[j] = iz;
+                (*elements)[fieldi] = ex;
+                ++fieldi;
+            }
+            if (errors)
+            {
+                result = new ErrorInitializer();
+                return;
+            }
+
+            StructLiteralExp *sle = new StructLiteralExp(i->loc, sd, elements, t);
+            if (!sd->fill(i->loc, elements, false))
+            {
+                result = new ErrorInitializer();
+                return;
+            }
+            sle->type = t;
+
+            ExpInitializer *ie = new ExpInitializer(i->loc, sle);
+            result = ::semantic(ie, sc, t, needInterpret);
+            return;
+        }
+        else if ((t->ty == Tdelegate || t->ty == Tpointer && t->nextOf()->ty == Tfunction) && i->value.dim == 0)
+        {
+            TOK tok = (t->ty == Tdelegate) ? TOKdelegate : TOKfunction;
+            /* Rewrite as empty delegate literal { }
+            */
+            Parameters *parameters = new Parameters;
+            Type *tf = new TypeFunction(parameters, NULL, 0, LINKd);
+            FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(i->loc, Loc(), tf, tok, NULL);
+            fd->fbody = new CompoundStatement(i->loc, new Statements());
+            fd->endloc = i->loc;
+            Expression *e = new FuncExp(i->loc, fd);
+            ExpInitializer *ie = new ExpInitializer(i->loc, e);
+            result = ::semantic(ie, sc, t, needInterpret);
+            return;
+        }
+
+        error(i->loc, "a struct is not a valid initializer for a %s", t->toChars());
+        result = new ErrorInitializer();
+    }
+
+    void visit(ArrayInitializer *i)
+    {
+        unsigned length;
+        const unsigned amax = 0x80000000;
+        bool errors = false;
+
+        //printf("ArrayInitializer::semantic(%s)\n", t->toChars());
+        if (i->sem)                            // if semantic() already run
+        {
+            result = i;
+            return;
+        }
+        i->sem = true;
+        t = t->toBasetype();
+        switch (t->ty)
+        {
+            case Tsarray:
+            case Tarray:
+                break;
+
+            case Tvector:
+                t = ((TypeVector *)t)->basetype;
+                break;
+
+            case Taarray:
+            case Tstruct:   // consider implicit constructor call
+                {
+                    Expression *e;
+                    // note: MyStruct foo = [1:2, 3:4] is correct code if MyStruct has a this(int[int])
+                    if (t->ty == Taarray || i->isAssociativeArray())
+                        e = i->toAssocArrayLiteral();
+                    else
+                        e = initializerToExpression(i);
+                    if (!e) // Bugzilla 13987
+                    {
+                        error(i->loc, "cannot use array to initialize %s", t->toChars());
+                        goto Lerr;
+                    }
+                    ExpInitializer *ei = new ExpInitializer(e->loc, e);
+                    result = ::semantic(ei, sc, t, needInterpret);
+                    return;
+                }
+            case Tpointer:
+                if (t->nextOf()->ty != Tfunction)
+                    break;
+
+            default:
+                error(i->loc, "cannot use array to initialize %s", t->toChars());
+                goto Lerr;
+        }
+
+        i->type = t;
+
+        length = 0;
+        for (size_t j = 0; j < i->index.dim; j++)
+        {
+            Expression *idx = i->index[j];
+            if (idx)
+            {
+                sc = sc->startCTFE();
+                idx = ::semantic(idx, sc);
+                sc = sc->endCTFE();
+                idx = idx->ctfeInterpret();
+                i->index[j] = idx;
+                const uinteger_t idxvalue = idx->toInteger();
+                if (idxvalue >= amax)
+                {
+                    error(i->loc, "array index %llu overflow", idxvalue);
+                    errors = true;
+                }
+                length = (unsigned)idx->toInteger();
+                if (idx->op == TOKerror)
+                    errors = true;
+            }
+
+            Initializer *val = i->value[j];
+            ExpInitializer *ei = val->isExpInitializer();
+            if (ei && !idx)
+                ei->expandTuples = true;
+            val = ::semantic(val, sc, t->nextOf(), needInterpret);
+            if (val->isErrorInitializer())
+                errors = true;
+
+            ei = val->isExpInitializer();
+            // found a tuple, expand it
+            if (ei && ei->exp->op == TOKtuple)
+            {
+                TupleExp *te = (TupleExp *)ei->exp;
+                i->index.remove(j);
+                i->value.remove(j);
+
+                for (size_t k = 0; k < te->exps->dim; ++k)
+                {
+                    Expression *e = (*te->exps)[k];
+                    i->index.insert(j + k, (Expression *)NULL);
+                    i->value.insert(j + k, new ExpInitializer(e->loc, e));
+                }
+                j--;
+                continue;
+            }
+            else
+            {
+                i->value[j] = val;
+            }
+
+            length++;
+            if (length == 0)
+            {
+                error(i->loc, "array dimension overflow");
+                goto Lerr;
+            }
+            if (length > i->dim)
+                i->dim = length;
+        }
+        if (t->ty == Tsarray)
+        {
+            uinteger_t edim = ((TypeSArray *)t)->dim->toInteger();
+            if (i->dim > edim)
+            {
+                error(i->loc, "array initializer has %u elements, but array length is %llu", i->dim, edim);
+                goto Lerr;
+            }
+        }
+        if (errors)
+            goto Lerr;
+        else
+        {
+            d_uns64 sz = t->nextOf()->size();
+            bool overflow = false;
+            const d_uns64 max = mulu((d_uns64)i->dim, sz, overflow);
+            if (overflow || max > amax)
+            {
+                error(i->loc, "array dimension %llu exceeds max of %llu", i->dim, (amax / sz));
+                goto Lerr;
+            }
+            result = i;
+            return;
+        }
+
+    Lerr:
+        result = new ErrorInitializer();
+    }
+
+    void visit(ExpInitializer *i)
+    {
+        //printf("ExpInitializer::semantic(%s), type = %s\n", i->exp->toChars(), t->toChars());
+        if (needInterpret) sc = sc->startCTFE();
+        i->exp = ::semantic(i->exp, sc);
+        i->exp = resolveProperties(sc, i->exp);
+        if (needInterpret) sc = sc->endCTFE();
+        if (i->exp->op == TOKerror)
+        {
+            result = new ErrorInitializer();
+            return;
+        }
+
+        unsigned int olderrors = global.errors;
+        if (needInterpret)
+        {
+            // If the result will be implicitly cast, move the cast into CTFE
+            // to avoid premature truncation of polysemous types.
+            // eg real [] x = [1.1, 2.2]; should use real precision.
+            if (i->exp->implicitConvTo(t))
+            {
+                i->exp = i->exp->implicitCastTo(sc, t);
+            }
+            if (!global.gag && olderrors != global.errors)
+            {
+                result = i;
+                return;
+            }
+            i->exp = i->exp->ctfeInterpret();
+        }
+        else
+        {
+            i->exp = i->exp->optimize(WANTvalue);
+        }
+        if (!global.gag && olderrors != global.errors)
+        {
+            result = i; // Failed, suppress duplicate error messages
+            return;
+        }
+
+        if (i->exp->type->ty == Ttuple && ((TypeTuple *)i->exp->type)->arguments->dim == 0)
+        {
+            Type *et = i->exp->type;
+            i->exp = new TupleExp(i->exp->loc, new Expressions());
+            i->exp->type = et;
+        }
+        if (i->exp->op == TOKtype)
+        {
+            i->exp->error("initializer must be an expression, not '%s'", i->exp->toChars());
+            result = new ErrorInitializer();
+            return;
+        }
+
+        // Make sure all pointers are constants
+        if (needInterpret && hasNonConstPointers(i->exp))
+        {
+            i->exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", i->exp->toChars());
+            result = new ErrorInitializer();
+            return;
+        }
+
+        Type *tb = t->toBasetype();
+        Type *ti = i->exp->type->toBasetype();
+
+        if (i->exp->op == TOKtuple && expandTuples && !i->exp->implicitConvTo(t))
+        {
+            result = new ExpInitializer(i->loc, i->exp);
+            return;
+        }
+
+        /* Look for case of initializing a static array with a too-short
+         * string literal, such as:
+         *  char[5] foo = "abc";
+         * Allow this by doing an explicit cast, which will lengthen the string
+         * literal.
+         */
+        if (i->exp->op == TOKstring && tb->ty == Tsarray)
+        {
+            StringExp *se = (StringExp *)i->exp;
+            Type *typeb = se->type->toBasetype();
+            TY tynto = tb->nextOf()->ty;
+            if (!se->committed &&
+                (typeb->ty == Tarray || typeb->ty == Tsarray) &&
+                (tynto == Tchar || tynto == Twchar || tynto == Tdchar) &&
+                se->numberOfCodeUnits(tynto) < ((TypeSArray *)tb)->dim->toInteger())
+            {
+                i->exp = se->castTo(sc, t);
+                goto L1;
+            }
+        }
+
+        // Look for implicit constructor call
+        if (tb->ty == Tstruct &&
+            !(ti->ty == Tstruct && tb->toDsymbol(sc) == ti->toDsymbol(sc)) &&
+            !i->exp->implicitConvTo(t))
+        {
+            StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+            if (sd->ctor)
+            {
+                // Rewrite as S().ctor(exp)
+                Expression *e;
+                e = new StructLiteralExp(i->loc, sd, NULL);
+                e = new DotIdExp(i->loc, e, Id::ctor);
+                e = new CallExp(i->loc, e, i->exp);
+                e = ::semantic(e, sc);
+                if (needInterpret)
+                    i->exp = e->ctfeInterpret();
+                else
+                    i->exp = e->optimize(WANTvalue);
+            }
+        }
+
+        // Look for the case of statically initializing an array
+        // with a single member.
+        if (tb->ty == Tsarray &&
+            !tb->nextOf()->equals(ti->toBasetype()->nextOf()) &&
+            i->exp->implicitConvTo(tb->nextOf())
+           )
+        {
+            /* If the variable is not actually used in compile time, array creation is
+             * redundant. So delay it until invocation of toExpression() or toDt().
+             */
+            t = tb->nextOf();
+        }
+
+        if (i->exp->implicitConvTo(t))
+        {
+            i->exp = i->exp->implicitCastTo(sc, t);
+        }
+        else
+        {
+            // Look for mismatch of compile-time known length to emit
+            // better diagnostic message, as same as AssignExp::semantic.
+            if (tb->ty == Tsarray &&
+                i->exp->implicitConvTo(tb->nextOf()->arrayOf()) > MATCHnomatch)
+            {
+                uinteger_t dim1 = ((TypeSArray *)tb)->dim->toInteger();
+                uinteger_t dim2 = dim1;
+                if (i->exp->op == TOKarrayliteral)
+                {
+                    ArrayLiteralExp *ale = (ArrayLiteralExp *)i->exp;
+                    dim2 = ale->elements ? ale->elements->dim : 0;
+                }
+                else if (i->exp->op == TOKslice)
+                {
+                    Type *tx = toStaticArrayType((SliceExp *)i->exp);
+                    if (tx)
+                        dim2 = ((TypeSArray *)tx)->dim->toInteger();
+                }
+                if (dim1 != dim2)
+                {
+                    i->exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
+                    i->exp = new ErrorExp();
+                }
+            }
+            i->exp = i->exp->implicitCastTo(sc, t);
+        }
+    L1:
+        if (i->exp->op == TOKerror)
+        {
+            result = i;
+            return;
+        }
+        if (needInterpret)
+            i->exp = i->exp->ctfeInterpret();
+        else
+            i->exp = i->exp->optimize(WANTvalue);
+        //printf("-ExpInitializer::semantic(): "); i->exp->print();
+        result = i;
+    }
+};
+
+// Performs semantic analisys on Initializer AST nodes
+Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret)
+{
+    InitializerSemanticVisitor v = InitializerSemanticVisitor(sc, t, needInterpret);
+    init->accept(&v);
+    return v.result;
+}
+
+class InferTypeVisitor : public Visitor
+{
+public:
+    Initializer *result;
+    Scope *sc;
+
+    InferTypeVisitor(Scope *sc)
+    {
+        this->result = NULL;
+        this->sc = sc;
+    }
+
+    void visit(ErrorInitializer *i)
+    {
+        result = i;
+    }
+
+    void visit(VoidInitializer *i)
+    {
+        error(i->loc, "cannot infer type from void initializer");
+        result = new ErrorInitializer();
+    }
+
+    void visit(StructInitializer *i)
+    {
+        error(i->loc, "cannot infer type from struct initializer");
+        result = new ErrorInitializer();
+    }
+
+    void visit(ArrayInitializer *init)
+    {
+        //printf("ArrayInitializer::inferType() %s\n", init->toChars());
+        Expressions *keys = NULL;
+        Expressions *values;
+        if (init->isAssociativeArray())
+        {
+            keys = new Expressions();
+            keys->setDim(init->value.dim);
+            values = new Expressions();
+            values->setDim(init->value.dim);
+
+            for (size_t i = 0; i < init->value.dim; i++)
+            {
+                Expression *e = init->index[i];
+                if (!e)
+                    goto Lno;
+                (*keys)[i] = e;
+
+                Initializer *iz = init->value[i];
+                if (!iz)
+                    goto Lno;
+                iz = inferType(iz, sc);
+                if (iz->isErrorInitializer())
+                {
+                    result = iz;
+                    return;
+                }
+                assert(iz->isExpInitializer());
+                (*values)[i] = ((ExpInitializer *)iz)->exp;
+                assert((*values)[i]->op != TOKerror);
+            }
+
+            Expression *e = new AssocArrayLiteralExp(init->loc, keys, values);
+            ExpInitializer *ei = new ExpInitializer(init->loc, e);
+            result = inferType(ei, sc);
+            return;
+        }
+        else
+        {
+            Expressions *elements = new Expressions();
+            elements->setDim(init->value.dim);
+            elements->zero();
+
+            for (size_t i = 0; i < init->value.dim; i++)
+            {
+                assert(!init->index[i]);  // already asserted by isAssociativeArray()
+
+                Initializer *iz = init->value[i];
+                if (!iz)
+                    goto Lno;
+                iz = inferType(iz, sc);
+                if (iz->isErrorInitializer())
+                {
+                    result = iz;
+                    return;
+                }
+                assert(iz->isExpInitializer());
+                (*elements)[i] = ((ExpInitializer *)iz)->exp;
+                assert((*elements)[i]->op != TOKerror);
+            }
+
+            Expression *e = new ArrayLiteralExp(init->loc, elements);
+            ExpInitializer *ei = new ExpInitializer(init->loc, e);
+            result = inferType(ei, sc);
+            return;
+        }
+    Lno:
+        if (keys)
+        {
+            delete keys;
+            delete values;
+            error(init->loc, "not an associative array initializer");
+        }
+        else
+        {
+            error(init->loc, "cannot infer type from array initializer");
+        }
+        result = new ErrorInitializer();
+    }
+
+    void visit(ExpInitializer *init)
+    {
+        //printf("ExpInitializer::inferType() %s\n", init->toChars());
+        init->exp = ::semantic(init->exp, sc);
+        init->exp = resolveProperties(sc, init->exp);
+
+        if (init->exp->op == TOKscope)
+        {
+            ScopeExp *se = (ScopeExp *)init->exp;
+            TemplateInstance *ti = se->sds->isTemplateInstance();
+            if (ti && ti->semanticRun == PASSsemantic && !ti->aliasdecl)
+                se->error("cannot infer type from %s %s, possible circular dependency", se->sds->kind(), se->toChars());
+            else
+                se->error("cannot infer type from %s %s", se->sds->kind(), se->toChars());
+            result = new ErrorInitializer();
+            return;
+        }
+
+        // Give error for overloaded function addresses
+        bool hasOverloads = false;
+        if (FuncDeclaration *f = isFuncAddress(init->exp, &hasOverloads))
+        {
+            if (f->checkForwardRef(init->loc))
+            {
+                result = new ErrorInitializer();
+                return;
+            }
+
+            if (hasOverloads && !f->isUnique())
+            {
+                init->exp->error("cannot infer type from overloaded function symbol %s", init->exp->toChars());
+                result = new ErrorInitializer();
+                return;
+            }
+        }
+        if (init->exp->op == TOKaddress)
+        {
+            AddrExp *ae = (AddrExp *)init->exp;
+            if (ae->e1->op == TOKoverloadset)
+            {
+                init->exp->error("cannot infer type from overloaded function symbol %s", init->exp->toChars());
+                result = new ErrorInitializer();
+                return;
+            }
+        }
+
+        if (init->exp->op == TOKerror)
+        {
+            result = new ErrorInitializer();
+            return;
+        }
+        if (!init->exp->type)
+        {
+            result = new ErrorInitializer();
+            return;
+        }
+        result = init;
+    }
+};
+
+/* Translates to an expression to infer type.
+ * Returns ExpInitializer or ErrorInitializer.
+ */
+Initializer *inferType(Initializer *init, Scope *sc)
+{
+    InferTypeVisitor v = InferTypeVisitor(sc);
+    init->accept(&v);
+    return v.result;
+}
+
+class InitToExpressionVisitor : public Visitor
+{
+public:
+    Expression *result;
+    Type *itype;
+
+    InitToExpressionVisitor(Type *itype)
+    {
+        this->result = NULL;
+        this->itype = itype;
+    }
+
+    void visit(ErrorInitializer *)
+    {
+        result = new ErrorExp();
+    }
+
+    void visit(VoidInitializer *)
+    {
+        result = NULL;
+    }
+
+    /***************************************
+     * This works by transforming a struct initializer into
+     * a struct literal. In the future, the two should be the
+     * same thing.
+     */
+    void visit(StructInitializer *)
+    {
+        // cannot convert to an expression without target 'ad'
+        result = NULL;
+    }
+
+    /********************************
+     * If possible, convert array initializer to array literal.
+     * Otherwise return NULL.
+     */
+
+    void visit(ArrayInitializer *init)
+    {
+        //printf("ArrayInitializer::toExpression(), dim = %d\n", init->dim);
+        //static int i; if (++i == 2) halt();
+
+        Expressions *elements;
+        unsigned edim;
+        const unsigned amax = 0x80000000;
+        Type *t = NULL;
+        if (init->type)
+        {
+            if (init->type == Type::terror)
+            {
+                result = new ErrorExp();
+                return;
+            }
+
+            t = init->type->toBasetype();
+            switch (t->ty)
+            {
+                case Tvector:
+                    t = ((TypeVector *)t)->basetype;
+                    /* fall through */
+
+                case Tsarray:
+                    {
+                        uinteger_t adim = ((TypeSArray *)t)->dim->toInteger();
+                        if (adim >= amax)
+                            goto Lno;
+                        edim = (unsigned)adim;
+                        break;
+                    }
+
+                case Tpointer:
+                case Tarray:
+                    edim = init->dim;
+                    break;
+
+                default:
+                    assert(0);
+            }
+        }
+        else
+        {
+            edim = (unsigned)init->value.dim;
+            for (size_t i = 0, j = 0; i < init->value.dim; i++, j++)
+            {
+                if (init->index[i])
+                {
+                    if (init->index[i]->op == TOKint64)
+                    {
+                        const uinteger_t idxval = init->index[i]->toInteger();
+                        if (idxval >= amax)
+                            goto Lno;
+                        j = (size_t)idxval;
+                    }
+                    else
+                        goto Lno;
+                }
+                if (j >= edim)
+                    edim = (unsigned)(j + 1);
+            }
+        }
+
+        elements = new Expressions();
+        elements->setDim(edim);
+        elements->zero();
+        for (size_t i = 0, j = 0; i < init->value.dim; i++, j++)
+        {
+            if (init->index[i])
+                j = (size_t)(init->index[i])->toInteger();
+            assert(j < edim);
+            Initializer *iz = init->value[i];
+            if (!iz)
+                goto Lno;
+            Expression *ex = initializerToExpression(iz);
+            if (!ex)
+            {
+                goto Lno;
+            }
+            (*elements)[j] = ex;
+        }
+
+        /* Fill in any missing elements with the default initializer
+        */
+        {
+            Expression *_init = NULL;
+            for (size_t i = 0; i < edim; i++)
+            {
+                if (!(*elements)[i])
+                {
+                    if (!init->type)
+                        goto Lno;
+                    if (!_init)
+                        _init = ((TypeNext *)t)->next->defaultInit();
+                    (*elements)[i] = _init;
+                }
+            }
+
+            /* Expand any static array initializers that are a single expression
+             * into an array of them
+             */
+            if (t)
+            {
+                Type *tn = t->nextOf()->toBasetype();
+                if (tn->ty == Tsarray)
+                {
+                    size_t dim = ((TypeSArray *)tn)->dim->toInteger();
+                    Type *te = tn->nextOf()->toBasetype();
+                    for (size_t i = 0; i < elements->dim; i++)
+                    {
+                        Expression *e = (*elements)[i];
+                        if (te->equals(e->type))
+                        {
+                            Expressions *elements2 = new Expressions();
+                            elements2->setDim(dim);
+                            for (size_t j = 0; j < dim; j++)
+                                (*elements2)[j] = e;
+                            e = new ArrayLiteralExp(e->loc, elements2);
+                            e->type = tn;
+                            (*elements)[i] = e;
+                        }
+                    }
+                }
+            }
+
+            /* If any elements are errors, then the whole thing is an error
+            */
+            for (size_t i = 0; i < edim; i++)
+            {
+                Expression *e = (*elements)[i];
+                if (e->op == TOKerror)
+                {
+                    result = e;
+                    return;
+                }
+            }
+
+            Expression *e = new ArrayLiteralExp(init->loc, elements);
+            e->type = init->type;
+            result = e;
+            return;
+        }
+
+    Lno:
+        result = NULL;
+    }
+
+    void visit(ExpInitializer *i)
+    {
+        if (itype)
+        {
+            //printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype->toChars(), i->exp->toChars());
+            Type *tb = itype->toBasetype();
+            Expression *e = (i->exp->op == TOKconstruct || i->exp->op == TOKblit) ? ((AssignExp *)i->exp)->e2 : i->exp;
+            if (tb->ty == Tsarray && e->implicitConvTo(tb->nextOf()))
+            {
+                TypeSArray *tsa = (TypeSArray *)tb;
+                size_t d = (size_t)tsa->dim->toInteger();
+                Expressions *elements = new Expressions();
+                elements->setDim(d);
+                for (size_t i = 0; i < d; i++)
+                    (*elements)[i] = e;
+                ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, elements);
+                ae->type = itype;
+                result = ae;
+                return;
+            }
+        }
+        result = i->exp;
+    }
+};
+
+Expression *initializerToExpression(Initializer *i, Type *t)
+{
+    InitToExpressionVisitor v = InitToExpressionVisitor(t);
+    i->accept(&v);
+    return v.result;
+}
diff --git a/gcc/d/dfrontend/inline.c b/gcc/d/dfrontend/inline.c
new file mode 100644
index 00000000000..c9a8276cf36
--- /dev/null
+++ b/gcc/d/dfrontend/inline.c
@@ -0,0 +1,1938 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/inline.c
+ */
+
+// Routines to perform function inlining
+
+#define LOG 0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>                     // memset()
+
+#include "id.h"
+#include "init.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "expression.h"
+#include "statement.h"
+#include "mtype.h"
+#include "scope.h"
+#include "attrib.h"
+#include "template.h"
+#include "module.h"
+#include "tokens.h"
+
+static void expandInline(Loc callLoc, FuncDeclaration *fd, FuncDeclaration *parent,
+    Expression *eret, Expression *ethis, Expressions *arguments, bool asStatements,
+    Expression **eresult, Statement **sresult, bool *again);
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+bool canInline(FuncDeclaration *fd, int hasthis, int hdrscan, bool statementsToo);
+Expression *initializerToExpression(Initializer *i, Type *t = NULL);
+int inlineCostExpression(Expression *e);
+int inlineCostFunction(FuncDeclaration *fd, bool hasthis, bool hdrscan);
+bool tooCostly(int cost);
+const int COST_MAX = 250;
+
+/* ======================== Perform the inlining ============================== */
+
+/* Inlining is done by:
+ * o    Converting to an Expression
+ * o    Copying the trees of the function to be inlined
+ * o    Renaming the variables
+ */
+
+struct InlineDoState
+{
+    // inline context
+    VarDeclaration *vthis;
+    Dsymbols from;      // old Dsymbols
+    Dsymbols to;        // parallel array of new Dsymbols
+    Dsymbol *parent;    // new parent
+    FuncDeclaration *fd; // function being inlined (old parent)
+    // inline result
+    bool foundReturn;
+};
+
+Expression *doInline(Statement *s, InlineDoState *ids);
+Expression *doInline(Expression *e, InlineDoState *ids);
+
+/* -------------------------------------------------------------------- */
+
+Statement *inlineAsStatement(Statement *s, InlineDoState *ids)
+{
+    class InlineAsStatement : public Visitor
+    {
+    public:
+        InlineDoState *ids;
+        Statement *result;
+
+        InlineAsStatement(InlineDoState *ids)
+            : ids(ids)
+        {
+            result = NULL;
+        }
+
+        void visit(Statement *s)
+        {
+            assert(0); // default is we can't inline it
+        }
+
+        void visit(ExpStatement *s)
+        {
+        #if LOG
+            if (s->exp) printf("ExpStatement::inlineAsStatement() '%s'\n", s->exp->toChars());
+        #endif
+            result = new ExpStatement(s->loc, s->exp ? doInline(s->exp, ids) : NULL);
+        }
+
+        void visit(CompoundStatement *s)
+        {
+            //printf("CompoundStatement::inlineAsStatement() %d\n", s->statements->dim);
+            Statements *as = new Statements();
+            as->reserve(s->statements->dim);
+            for (size_t i = 0; i < s->statements->dim; i++)
+            {
+                Statement *sx = (*s->statements)[i];
+                if (sx)
+                {
+                    as->push(inlineAsStatement(sx, ids));
+                    if (ids->foundReturn)
+                        break;
+                }
+                else
+                    as->push(NULL);
+            }
+            result = new CompoundStatement(s->loc, as);
+        }
+
+        void visit(UnrolledLoopStatement *s)
+        {
+            //printf("UnrolledLoopStatement::inlineAsStatement() %d\n", s->statements->dim);
+            Statements *as = new Statements();
+            as->reserve(s->statements->dim);
+            for (size_t i = 0; i < s->statements->dim; i++)
+            {
+                Statement *sx = (*s->statements)[i];
+                if (sx)
+                {
+                    as->push(inlineAsStatement(sx, ids));
+                    if (ids->foundReturn)
+                        break;
+                }
+                else
+                    as->push(NULL);
+            }
+            result = new UnrolledLoopStatement(s->loc, as);
+        }
+
+        void visit(ScopeStatement *s)
+        {
+            //printf("ScopeStatement::inlineAsStatement() %d\n", s->statement->dim);
+            result = s->statement ? new ScopeStatement(s->loc, inlineAsStatement(s->statement, ids), s->endloc) : s;
+        }
+
+        void visit(IfStatement *s)
+        {
+            assert(!s->prm);
+
+            Expression *condition = s->condition ? doInline(s->condition, ids) : NULL;
+            Statement *ifbody = s->ifbody ? inlineAsStatement(s->ifbody, ids) : NULL;
+            bool bodyReturn = ids->foundReturn;
+            ids->foundReturn = false;
+            Statement *elsebody = s->elsebody ? inlineAsStatement(s->elsebody, ids) : NULL;
+            ids->foundReturn = ids->foundReturn && bodyReturn;
+
+            result = new IfStatement(s->loc, s->prm, condition, ifbody, elsebody, s->endloc);
+        }
+
+        void visit(ReturnStatement *s)
+        {
+            //printf("ReturnStatement::inlineAsStatement() '%s'\n", s->exp ? s->exp->toChars() : "");
+            ids->foundReturn = true;
+            if (s->exp) // Bugzilla 14560: 'return' must not leave in the expand result
+                result = new ReturnStatement(s->loc, doInline(s->exp, ids));
+        }
+
+        void visit(ImportStatement *s)
+        {
+            result = NULL;
+        }
+
+        void visit(ForStatement *s)
+        {
+            //printf("ForStatement::inlineAsStatement()\n");
+            Statement *init = s->_init ? inlineAsStatement(s->_init, ids) : NULL;
+            Expression *condition = s->condition ? doInline(s->condition, ids) : NULL;
+            Expression *increment = s->increment ? doInline(s->increment, ids) : NULL;
+            Statement *body = s->_body ? inlineAsStatement(s->_body, ids) : NULL;
+            result = new ForStatement(s->loc, init, condition, increment, body, s->endloc);
+        }
+
+        void visit(ThrowStatement *s)
+        {
+            //printf("ThrowStatement::inlineAsStatement() '%s'\n", s->exp->toChars());
+            result = new ThrowStatement(s->loc, doInline(s->exp, ids));
+        }
+    };
+
+    InlineAsStatement v(ids);
+    s->accept(&v);
+    return v.result;
+}
+
+/* -------------------------------------------------------------------- */
+
+Expression *doInline(Statement *s, InlineDoState *ids)
+{
+    class InlineStatement : public Visitor
+    {
+    public:
+        InlineDoState *ids;
+        Expression *result;
+
+        InlineStatement(InlineDoState *ids)
+            : ids(ids)
+        {
+            result = NULL;
+        }
+
+        void visit(Statement *s)
+        {
+            printf("Statement::doInline()\n%s\n", s->toChars());
+            fflush(stdout);
+            assert(0); // default is we can't inline it
+        }
+
+        void visit(ExpStatement *s)
+        {
+        #if LOG
+            if (s->exp) printf("ExpStatement::doInline() '%s'\n", s->exp->toChars());
+        #endif
+            result = s->exp ? doInline(s->exp, ids) : NULL;
+        }
+
+        void visit(CompoundStatement *s)
+        {
+            //printf("CompoundStatement::doInline() %d\n", s->statements->dim);
+            for (size_t i = 0; i < s->statements->dim; i++)
+            {
+                Statement *sx =  (*s->statements)[i];
+                if (sx)
+                {
+                    Expression *e = doInline(sx, ids);
+                    result = Expression::combine(result, e);
+                    if (ids->foundReturn)
+                        break;
+
+                }
+            }
+        }
+
+        void visit(UnrolledLoopStatement *s)
+        {
+            //printf("UnrolledLoopStatement::doInline() %d\n", s->statements->dim);
+            for (size_t i = 0; i < s->statements->dim; i++)
+            {
+                Statement *sx =  (*s->statements)[i];
+                if (sx)
+                {
+                    Expression *e = doInline(sx, ids);
+                    result = Expression::combine(result, e);
+                    if (ids->foundReturn)
+                        break;
+
+                }
+            }
+        }
+
+        void visit(ScopeStatement *s)
+        {
+            result = s->statement ? doInline(s->statement, ids) : NULL;
+        }
+
+        void visit(IfStatement *s)
+        {
+            assert(!s->prm);
+            Expression *econd = doInline(s->condition, ids);
+            assert(econd);
+            Expression *e1 = s->ifbody ? doInline(s->ifbody, ids) : NULL;
+            bool bodyReturn = ids->foundReturn;
+            ids->foundReturn = false;
+            Expression *e2 = s->elsebody ? doInline(s->elsebody, ids) : NULL;
+            if (e1 && e2)
+            {
+                result = new CondExp(econd->loc, econd, e1, e2);
+                result->type = e1->type;
+                if (result->type->ty == Ttuple)
+                {
+                    e1->type = Type::tvoid;
+                    e2->type = Type::tvoid;
+                    result->type = Type::tvoid;
+                }
+            }
+            else if (e1)
+            {
+                result = new AndAndExp(econd->loc, econd, e1);
+                result->type = Type::tvoid;
+            }
+            else if (e2)
+            {
+                result = new OrOrExp(econd->loc, econd, e2);
+                result->type = Type::tvoid;
+            }
+            else
+            {
+                result = econd;
+            }
+            ids->foundReturn = ids->foundReturn && bodyReturn;
+        }
+
+        void visit(ReturnStatement *s)
+        {
+            //printf("ReturnStatement::doInline() '%s'\n", s->exp ? s->exp->toChars() : "");
+            ids->foundReturn = true;
+            result = s->exp ? doInline(s->exp, ids) : NULL;
+        }
+
+        void visit(ImportStatement *s)
+        {
+        }
+    };
+
+    InlineStatement v(ids);
+    s->accept(&v);
+    return v.result;
+}
+
+/* --------------------------------------------------------------- */
+
+Expression *doInline(Expression *e, InlineDoState *ids)
+{
+    class InlineExpression : public Visitor
+    {
+    public:
+        InlineDoState *ids;
+        Expression *result;
+
+        InlineExpression(InlineDoState *ids)
+            : ids(ids)
+        {
+            result = NULL;
+        }
+
+        /******************************
+         * Perform doInline() on an array of Expressions.
+         */
+        Expressions *arrayExpressiondoInline(Expressions *a)
+        {
+            if (!a)
+                return NULL;
+
+            Expressions *newa = new Expressions();
+            newa->setDim(a->dim);
+
+            for (size_t i = 0; i < a->dim; i++)
+            {
+                Expression *e = (*a)[i];
+                if (e)
+                    e = doInline(e, ids);
+                (*newa)[i] = e;
+            }
+            return newa;
+        }
+
+        void visit(Expression *e)
+        {
+            //printf("Expression::doInline(%s): %s\n", Token::toChars(e->op), e->toChars());
+            result = e->copy();
+        }
+
+        void visit(SymOffExp *e)
+        {
+            //printf("SymOffExp::doInline(%s)\n", e->toChars());
+            for (size_t i = 0; i < ids->from.dim; i++)
+            {
+                if (e->var == ids->from[i])
+                {
+                    SymOffExp *se = (SymOffExp *)e->copy();
+                    se->var = (Declaration *)ids->to[i];
+                    result = se;
+                    return;
+                }
+            }
+            result = e;
+        }
+
+        void visit(VarExp *e)
+        {
+            //printf("VarExp::doInline(%s)\n", e->toChars());
+            for (size_t i = 0; i < ids->from.dim; i++)
+            {
+                if (e->var == ids->from[i])
+                {
+                    VarExp *ve = (VarExp *)e->copy();
+                    ve->var = (Declaration *)ids->to[i];
+                    result = ve;
+                    return;
+                }
+            }
+            if (ids->fd && e->var == ids->fd->vthis)
+            {
+                result = new VarExp(e->loc, ids->vthis);
+                result->type = e->type;
+                return;
+            }
+
+            /* Inlining context pointer access for nested referenced variables.
+             * For example:
+             *      auto fun() {
+             *        int i = 40;
+             *        auto foo() {
+             *          int g = 2;
+             *          struct Result {
+             *            auto bar() { return i + g; }
+             *          }
+             *          return Result();
+             *        }
+             *        return foo();
+             *      }
+             *      auto t = fun();
+             * 'i' and 'g' are nested referenced variables in Result.bar(), so:
+             *      auto x = t.bar();
+             * should be inlined to:
+             *      auto x = *(t.vthis.vthis + i->voffset) + *(t.vthis + g->voffset)
+             */
+            VarDeclaration *v = e->var->isVarDeclaration();
+            if (v && v->nestedrefs.dim && ids->vthis)
+            {
+                Dsymbol *s = ids->fd;
+                FuncDeclaration *fdv = v->toParent()->isFuncDeclaration();
+                assert(fdv);
+                result = new VarExp(e->loc, ids->vthis);
+                result->type = ids->vthis->type;
+                while (s != fdv)
+                {
+                    FuncDeclaration *f = s->isFuncDeclaration();
+                    if (AggregateDeclaration *ad = s->isThis())
+                    {
+                        assert(ad->vthis);
+                        result = new DotVarExp(e->loc, result, ad->vthis);
+                        result->type = ad->vthis->type;
+                        s = ad->toParent2();
+                    }
+                    else if (f && f->isNested())
+                    {
+                        assert(f->vthis);
+                        if (f->hasNestedFrameRefs())
+                        {
+                            result = new DotVarExp(e->loc, result, f->vthis);
+                            result->type = f->vthis->type;
+                        }
+                        s = f->toParent2();
+                    }
+                    else
+                        assert(0);
+                    assert(s);
+                }
+                result = new DotVarExp(e->loc, result, v);
+                result->type = v->type;
+                //printf("\t==> result = %s, type = %s\n", result->toChars(), result->type->toChars());
+                return;
+            }
+
+            result = e;
+        }
+
+        void visit(ThisExp *e)
+        {
+            //if (!ids->vthis)
+                //e->error("no 'this' when inlining %s", ids->parent->toChars());
+            if (!ids->vthis)
+            {
+                result = e;
+                return;
+            }
+
+            result = new VarExp(e->loc, ids->vthis);
+            result->type = e->type;
+        }
+
+        void visit(SuperExp *e)
+        {
+            assert(ids->vthis);
+
+            result = new VarExp(e->loc, ids->vthis);
+            result->type = e->type;
+        }
+
+        void visit(DeclarationExp *e)
+        {
+            //printf("DeclarationExp::doInline(%s)\n", e->toChars());
+            if (VarDeclaration *vd = e->declaration->isVarDeclaration())
+            {
+        #if 0
+                // Need to figure this out before inlining can work for tuples
+                TupleDeclaration *td = vd->toAlias()->isTupleDeclaration();
+                if (td)
+                {
+                    for (size_t i = 0; i < td->objects->dim; i++)
+                    {
+                        DsymbolExp *se = (*td->objects)[i];
+                        assert(se->op == TOKdsymbol);
+                        se->s;
+                    }
+                    result = st->objects->dim;
+                    return;
+                }
+        #endif
+                if (!vd->isStatic())
+                {
+                    if (ids->fd && vd == ids->fd->nrvo_var)
+                    {
+                        for (size_t i = 0; i < ids->from.dim; i++)
+                        {
+                            if (vd == ids->from[i])
+                            {
+                                if (vd->_init && !vd->_init->isVoidInitializer())
+                                {
+                                    result = initializerToExpression(vd->_init);
+                                    assert(result);
+                                    result = doInline(result, ids);
+                                }
+                                else
+                                    result = new IntegerExp(vd->_init->loc, 0, Type::tint32);
+                                return;
+                            }
+                        }
+                    }
+                    VarDeclaration *vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->_init);
+                    memcpy((void *)vto, (void *)vd, sizeof(VarDeclaration));
+                    vto->parent = ids->parent;
+                    vto->csym = NULL;
+                    vto->isym = NULL;
+
+                    ids->from.push(vd);
+                    ids->to.push(vto);
+
+                    if (vd->_init)
+                    {
+                        if (vd->_init->isVoidInitializer())
+                        {
+                            vto->_init = new VoidInitializer(vd->_init->loc);
+                        }
+                        else
+                        {
+                            Expression *ei = initializerToExpression(vd->_init);
+                            assert(ei);
+                            vto->_init = new ExpInitializer(ei->loc, doInline(ei, ids));
+                        }
+                    }
+                    DeclarationExp *de = (DeclarationExp *)e->copy();
+                    de->declaration = vto;
+                    result = de;
+                    return;
+                }
+            }
+            /* This needs work, like DeclarationExp::toElem(), if we are
+             * to handle TemplateMixin's. For now, we just don't inline them.
+             */
+            visit((Expression *)e);
+        }
+
+        void visit(TypeidExp *e)
+        {
+            //printf("TypeidExp::doInline(): %s\n", e->toChars());
+            TypeidExp *te = (TypeidExp *)e->copy();
+            if (Expression *ex = isExpression(te->obj))
+            {
+                te->obj = doInline(ex, ids);
+            }
+            else
+                assert(isType(te->obj));
+            result = te;
+        }
+
+        void visit(NewExp *e)
+        {
+            //printf("NewExp::doInline(): %s\n", e->toChars());
+            NewExp *ne = (NewExp *)e->copy();
+
+            if (e->thisexp)
+                ne->thisexp = doInline(e->thisexp, ids);
+            ne->newargs = arrayExpressiondoInline(e->newargs);
+            ne->arguments = arrayExpressiondoInline(e->arguments);
+            result = ne;
+
+            semanticTypeInfo(NULL, e->type);
+        }
+
+        void visit(DeleteExp *e)
+        {
+            visit((UnaExp *)e);
+
+            Type *tb = e->e1->type->toBasetype();
+            if (tb->ty == Tarray)
+            {
+                Type *tv = tb->nextOf()->baseElemOf();
+                if (tv->ty == Tstruct)
+                {
+                    TypeStruct *ts = (TypeStruct *)tv;
+                    StructDeclaration *sd = ts->sym;
+                    if (sd->dtor)
+                        semanticTypeInfo(NULL, ts);
+                }
+            }
+        }
+
+        void visit(UnaExp *e)
+        {
+            UnaExp *ue = (UnaExp *)e->copy();
+
+            ue->e1 = doInline(e->e1, ids);
+            result = ue;
+        }
+
+        void visit(AssertExp *e)
+        {
+            AssertExp *ae = (AssertExp *)e->copy();
+
+            ae->e1 = doInline(e->e1, ids);
+            if (e->msg)
+                ae->msg = doInline(e->msg, ids);
+            result = ae;
+        }
+
+        void visit(BinExp *e)
+        {
+            BinExp *be = (BinExp *)e->copy();
+
+            be->e1 = doInline(e->e1, ids);
+            be->e2 = doInline(e->e2, ids);
+            result = be;
+        }
+
+        void visit(CallExp *e)
+        {
+            CallExp *ce = (CallExp *)e->copy();
+
+            ce->e1 = doInline(e->e1, ids);
+            ce->arguments = arrayExpressiondoInline(e->arguments);
+            result = ce;
+        }
+
+        void visit(AssignExp *e)
+        {
+            visit((BinExp *)e);
+
+            if (e->e1->op == TOKarraylength)
+            {
+                ArrayLengthExp *ale = (ArrayLengthExp *)e->e1;
+                Type *tn = ale->e1->type->toBasetype()->nextOf();
+                semanticTypeInfo(NULL, tn);
+            }
+        }
+
+        void visit(EqualExp *e)
+        {
+            visit((BinExp *)e);
+
+            Type *t1 = e->e1->type->toBasetype();
+            if (t1->ty == Tarray || t1->ty == Tsarray)
+            {
+                Type *t = t1->nextOf()->toBasetype();
+                while (t->toBasetype()->nextOf())
+                    t = t->nextOf()->toBasetype();
+                if (t->ty == Tstruct)
+                    semanticTypeInfo(NULL, t);
+            }
+            else if (t1->ty == Taarray)
+            {
+                semanticTypeInfo(NULL, t1);
+            }
+        }
+
+        void visit(IndexExp *e)
+        {
+            IndexExp *are = (IndexExp *)e->copy();
+
+            are->e1 = doInline(e->e1, ids);
+
+            if (e->lengthVar)
+            {
+                //printf("lengthVar\n");
+                VarDeclaration *vd = e->lengthVar;
+
+                VarDeclaration *vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->_init);
+                memcpy((void*)vto, (void*)vd, sizeof(VarDeclaration));
+                vto->parent = ids->parent;
+                vto->csym = NULL;
+                vto->isym = NULL;
+
+                ids->from.push(vd);
+                ids->to.push(vto);
+
+                if (vd->_init && !vd->_init->isVoidInitializer())
+                {
+                    ExpInitializer *ie = vd->_init->isExpInitializer();
+                    assert(ie);
+                    vto->_init = new ExpInitializer(ie->loc, doInline(ie->exp, ids));
+                }
+
+                are->lengthVar = vto;
+            }
+            are->e2 = doInline(e->e2, ids);
+            result = are;
+        }
+
+        void visit(SliceExp *e)
+        {
+            SliceExp *are = (SliceExp *)e->copy();
+
+            are->e1 = doInline(e->e1, ids);
+
+            if (e->lengthVar)
+            {
+                //printf("lengthVar\n");
+                VarDeclaration *vd = e->lengthVar;
+
+                VarDeclaration *vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->_init);
+                memcpy((void*)vto, (void*)vd, sizeof(VarDeclaration));
+                vto->parent = ids->parent;
+                vto->csym = NULL;
+                vto->isym = NULL;
+
+                ids->from.push(vd);
+                ids->to.push(vto);
+
+                if (vd->_init && !vd->_init->isVoidInitializer())
+                {
+                    ExpInitializer *ie = vd->_init->isExpInitializer();
+                    assert(ie);
+                    vto->_init = new ExpInitializer(ie->loc, doInline(ie->exp, ids));
+                }
+
+                are->lengthVar = vto;
+            }
+            if (e->lwr)
+                are->lwr = doInline(e->lwr, ids);
+            if (e->upr)
+                are->upr = doInline(e->upr, ids);
+            result = are;
+        }
+
+        void visit(TupleExp *e)
+        {
+            TupleExp *ce = (TupleExp *)e->copy();
+
+            if (e->e0)
+                ce->e0 = doInline(e->e0, ids);
+            ce->exps = arrayExpressiondoInline(e->exps);
+            result = ce;
+        }
+
+        void visit(ArrayLiteralExp *e)
+        {
+            ArrayLiteralExp *ce = (ArrayLiteralExp *)e->copy();
+            if (ce->basis)
+                ce->basis = doInline(e->basis, ids);
+            ce->elements = arrayExpressiondoInline(e->elements);
+            result = ce;
+
+            semanticTypeInfo(NULL, e->type);
+        }
+
+        void visit(AssocArrayLiteralExp *e)
+        {
+            AssocArrayLiteralExp *ce = (AssocArrayLiteralExp *)e->copy();
+
+            ce->keys = arrayExpressiondoInline(e->keys);
+            ce->values = arrayExpressiondoInline(e->values);
+            result = ce;
+
+            semanticTypeInfo(NULL, e->type);
+        }
+
+        void visit(StructLiteralExp *e)
+        {
+            if (e->inlinecopy)
+            {
+                result = e->inlinecopy;
+                return;
+            }
+            StructLiteralExp *ce = (StructLiteralExp *)e->copy();
+
+            e->inlinecopy = ce;
+            ce->elements = arrayExpressiondoInline(e->elements);
+            e->inlinecopy = NULL;
+            result = ce;
+        }
+
+        void visit(ArrayExp *e)
+        {
+            ArrayExp *ce = (ArrayExp *)e->copy();
+
+            ce->e1 = doInline(e->e1, ids);
+            ce->arguments = arrayExpressiondoInline(e->arguments);
+            result = ce;
+        }
+
+        void visit(CondExp *e)
+        {
+            CondExp *ce = (CondExp *)e->copy();
+
+            ce->econd = doInline(e->econd, ids);
+            ce->e1 = doInline(e->e1, ids);
+            ce->e2 = doInline(e->e2, ids);
+            result = ce;
+        }
+    };
+
+    InlineExpression v(ids);
+    e->accept(&v);
+    return v.result;
+}
+
+/* ========== Walk the parse trees, and inline expand functions ============= */
+
+/* Walk the trees, looking for functions to inline.
+ * Inline any that can be.
+ */
+
+class InlineScanVisitor : public Visitor
+{
+public:
+    FuncDeclaration *parent; // function being scanned
+    // As the visit method cannot return a value, these variables
+    // are used to pass the result from 'visit' back to 'inlineScan'
+    Statement *sresult;
+    Expression *eresult;
+    bool again;
+
+    InlineScanVisitor()
+    {
+        this->parent = NULL;
+        this->sresult = NULL;
+        this->eresult = NULL;
+        this->again = false;
+    }
+
+    void visit(Statement *s)
+    {
+    }
+
+    Statement *inlineScanExpAsStatement(Expression **exp)
+    {
+        /* If there's a TOKcall at the top, then it may fail to inline
+         * as an Expression. Try to inline as a Statement instead.
+         */
+        if ((*exp)->op == TOKcall)
+        {
+            visitCallExp((CallExp *)(*exp), NULL, true);
+            if (eresult)
+                *exp = eresult;
+            Statement *s = sresult;
+            sresult = NULL;
+            eresult = NULL;
+            return s;
+        }
+
+        /* If there's a CondExp or CommaExp at the top, then its
+         * sub-expressions may be inlined as statements.
+         */
+        if ((*exp)->op == TOKquestion)
+        {
+            CondExp *e = (CondExp *)(*exp);
+            inlineScan(&e->econd);
+            Statement *s1 = inlineScanExpAsStatement(&e->e1);
+            Statement *s2 = inlineScanExpAsStatement(&e->e2);
+            if (!s1 && !s2)
+                return NULL;
+            Statement *ifbody = !s1 ? new ExpStatement(e->e1->loc, e->e1) : s1;
+            Statement *elsebody = !s2 ? new ExpStatement(e->e2->loc, e->e2) : s2;
+            return new IfStatement((*exp)->loc, NULL, e->econd, ifbody, elsebody, (*exp)->loc);
+        }
+        if ((*exp)->op == TOKcomma)
+        {
+            CommaExp *e = (CommaExp *)(*exp);
+            Statement *s1 = inlineScanExpAsStatement(&e->e1);
+            Statement *s2 = inlineScanExpAsStatement(&e->e2);
+            if (!s1 && !s2)
+                return NULL;
+            Statements *a = new Statements();
+            a->push(!s1 ? new ExpStatement(e->e1->loc, e->e1) : s1);
+            a->push(!s2 ? new ExpStatement(e->e2->loc, e->e2) : s2);
+            return new CompoundStatement((*exp)->loc, a);
+        }
+
+        // inline as an expression
+        inlineScan(exp);
+        return NULL;
+    }
+
+    void visit(ExpStatement *s)
+    {
+    #if LOG
+        printf("ExpStatement::inlineScan(%s)\n", s->toChars());
+    #endif
+        if (!s->exp)
+            return;
+
+        sresult = inlineScanExpAsStatement(&s->exp);
+    }
+
+    void visit(CompoundStatement *s)
+    {
+        for (size_t i = 0; i < s->statements->dim; i++)
+        {
+            inlineScan(&(*s->statements)[i]);
+        }
+    }
+
+    void visit(UnrolledLoopStatement *s)
+    {
+        for (size_t i = 0; i < s->statements->dim; i++)
+        {
+            inlineScan(&(*s->statements)[i]);
+        }
+    }
+
+    void visit(ScopeStatement *s)
+    {
+        inlineScan(&s->statement);
+    }
+
+    void visit(WhileStatement *s)
+    {
+        inlineScan(&s->condition);
+        inlineScan(&s->_body);
+    }
+
+    void visit(DoStatement *s)
+    {
+        inlineScan(&s->_body);
+        inlineScan(&s->condition);
+    }
+
+    void visit(ForStatement *s)
+    {
+        inlineScan(&s->_init);
+        inlineScan(&s->condition);
+        inlineScan(&s->increment);
+        inlineScan(&s->_body);
+    }
+
+    void visit(ForeachStatement *s)
+    {
+        inlineScan(&s->aggr);
+        inlineScan(&s->_body);
+    }
+
+    void visit(ForeachRangeStatement *s)
+    {
+        inlineScan(&s->lwr);
+        inlineScan(&s->upr);
+        inlineScan(&s->_body);
+    }
+
+    void visit(IfStatement *s)
+    {
+        inlineScan(&s->condition);
+        inlineScan(&s->ifbody);
+        inlineScan(&s->elsebody);
+    }
+
+    void visit(SwitchStatement *s)
+    {
+        //printf("SwitchStatement::inlineScan()\n");
+        inlineScan(&s->condition);
+        inlineScan(&s->_body);
+        Statement *sdefault = s->sdefault;
+        inlineScan(&sdefault);
+        s->sdefault = (DefaultStatement *)sdefault;
+        if (s->cases)
+        {
+            for (size_t i = 0; i < s->cases->dim; i++)
+            {
+                Statement *scase = (*s->cases)[i];
+                inlineScan(&scase);
+                (*s->cases)[i] = (CaseStatement *)scase;
+            }
+        }
+    }
+
+    void visit(CaseStatement *s)
+    {
+        //printf("CaseStatement::inlineScan()\n");
+        inlineScan(&s->exp);
+        inlineScan(&s->statement);
+    }
+
+    void visit(DefaultStatement *s)
+    {
+        inlineScan(&s->statement);
+    }
+
+    void visit(ReturnStatement *s)
+    {
+        //printf("ReturnStatement::inlineScan()\n");
+        inlineScan(&s->exp);
+    }
+
+    void visit(SynchronizedStatement *s)
+    {
+        inlineScan(&s->exp);
+        inlineScan(&s->_body);
+    }
+
+    void visit(WithStatement *s)
+    {
+        inlineScan(&s->exp);
+        inlineScan(&s->_body);
+    }
+
+    void visit(TryCatchStatement *s)
+    {
+        inlineScan(&s->_body);
+        if (s->catches)
+        {
+            for (size_t i = 0; i < s->catches->dim; i++)
+            {
+                Catch *c = (*s->catches)[i];
+                inlineScan(&c->handler);
+            }
+        }
+    }
+
+    void visit(TryFinallyStatement *s)
+    {
+        inlineScan(&s->_body);
+        inlineScan(&s->finalbody);
+    }
+
+    void visit(ThrowStatement *s)
+    {
+        inlineScan(&s->exp);
+    }
+
+    void visit(LabelStatement *s)
+    {
+        inlineScan(&s->statement);
+    }
+
+    void inlineScan(Statement **s)
+    {
+        if (!*s) return;
+        assert(sresult == NULL);
+        (*s)->accept(this);
+        if (sresult)
+        {
+            *s = sresult;
+            sresult = NULL;
+        }
+    }
+
+    /* -------------------------- */
+
+    void arrayInlineScan(Expressions *arguments)
+    {
+        if (arguments)
+        {
+            for (size_t i = 0; i < arguments->dim; i++)
+            {
+                inlineScan(&(*arguments)[i]);
+            }
+        }
+    }
+
+    void visit(Expression *e)
+    {
+    }
+
+    void scanVar(Dsymbol *s)
+    {
+        //printf("scanVar(%s %s)\n", s->kind(), s->toPrettyChars());
+        VarDeclaration *vd = s->isVarDeclaration();
+        if (vd)
+        {
+            TupleDeclaration *td = vd->toAlias()->isTupleDeclaration();
+            if (td)
+            {
+                for (size_t i = 0; i < td->objects->dim; i++)
+                {
+                    DsymbolExp *se = (DsymbolExp *)(*td->objects)[i];
+                    assert(se->op == TOKdsymbol);
+                    scanVar(se->s);    // TODO
+                }
+            }
+            else if (vd->_init)
+            {
+                if (ExpInitializer *ie = vd->_init->isExpInitializer())
+                {
+                    inlineScan(&ie->exp);
+                }
+            }
+        }
+        else
+        {
+            s->accept(this);
+        }
+    }
+
+    void visit(DeclarationExp *e)
+    {
+        //printf("DeclarationExp::inlineScan()\n");
+        scanVar(e->declaration);
+    }
+
+    void visit(UnaExp *e)
+    {
+        inlineScan(&e->e1);
+    }
+
+    void visit(AssertExp *e)
+    {
+        inlineScan(&e->e1);
+        inlineScan(&e->msg);
+    }
+
+    void visit(BinExp *e)
+    {
+        inlineScan(&e->e1);
+        inlineScan(&e->e2);
+    }
+
+    void visit(AssignExp *e)
+    {
+        // Look for NRVO, as inlining NRVO function returns require special handling
+        if (e->op == TOKconstruct && e->e2->op == TOKcall)
+        {
+            CallExp *ce = (CallExp *)e->e2;
+            if (ce->f && ce->f->nrvo_can && ce->f->nrvo_var)   // NRVO
+            {
+                if (e->e1->op == TOKvar)
+                {
+                    /* Inlining:
+                     *   S s = foo();   // initializing by rvalue
+                     *   S s = S(1);    // constrcutor call
+                     */
+                    Declaration *d = ((VarExp *)e->e1)->var;
+                    if (d->storage_class & (STCout | STCref))  // refinit
+                        goto L1;
+                }
+                else
+                {
+                    /* Inlining:
+                     *   this.field = foo();   // inside constructor
+                     */
+                    inlineScan(&e->e1);
+                }
+
+                visitCallExp(ce, e->e1, false);
+                if (eresult)
+                {
+                    //printf("call with nrvo: %s ==> %s\n", e->toChars(), eresult->toChars());
+                    return;
+                }
+            }
+        }
+    L1:
+        visit((BinExp *)e);
+    }
+
+    void visit(CallExp *e)
+    {
+        //printf("CallExp::inlineScan() %s\n", e->toChars())
+        visitCallExp(e, NULL, false);
+    }
+
+    /**************************************
+     * Check function call to see if can be inlined,
+     * and then inline it if it can.
+     * Params:
+     *  e = the function call
+     *  eret = if !null, then this is the lvalue of the nrvo function result
+     *  asStatements = if inline as statements rather than as an Expression
+     * Returns:
+     *  this->eresult if asStatements == false
+     *  this->sresult if asStatements == true
+     */
+    void visitCallExp(CallExp *e, Expression *eret, bool asStatements)
+    {
+        inlineScan(&e->e1);
+        arrayInlineScan(e->arguments);
+
+        //printf("visitCallExp() %s\n", e->toChars());
+        FuncDeclaration *fd = NULL;
+        if (e->e1->op == TOKvar)
+        {
+            VarExp *ve = (VarExp *)e->e1;
+            fd = ve->var->isFuncDeclaration();
+            if (fd && fd != parent && canInline(fd, 0, 0, asStatements))
+            {
+                expandInline(e->loc, fd, parent, eret, NULL, e->arguments, asStatements, &eresult, &sresult, &again);
+            }
+        }
+        else if (e->e1->op == TOKdotvar)
+        {
+            DotVarExp *dve = (DotVarExp *)e->e1;
+            fd = dve->var->isFuncDeclaration();
+
+            if (fd && fd != parent && canInline(fd, 1, 0, asStatements))
+            {
+                if (dve->e1->op == TOKcall &&
+                    dve->e1->type->toBasetype()->ty == Tstruct)
+                {
+                    /* To create ethis, we'll need to take the address
+                     * of dve->e1, but this won't work if dve->e1 is
+                     * a function call.
+                     */
+                }
+                else
+                {
+                    expandInline(e->loc, fd, parent, eret, dve->e1, e->arguments, asStatements, &eresult, &sresult, &again);
+                }
+            }
+        }
+        else
+            return;
+
+        if (global.params.verbose && (eresult || sresult))
+            fprintf(global.stdmsg, "inlined   %s =>\n          %s\n", fd->toPrettyChars(), parent->toPrettyChars());
+
+        if (eresult && e->type->ty != Tvoid)
+        {
+            Expression *ex = eresult;
+            while (ex->op == TOKcomma)
+            {
+                ex->type = e->type;
+                ex = ((CommaExp *)ex)->e2;
+            }
+            ex->type = e->type;
+        }
+    }
+
+    void visit(SliceExp *e)
+    {
+        inlineScan(&e->e1);
+        inlineScan(&e->lwr);
+        inlineScan(&e->upr);
+    }
+
+    void visit(TupleExp *e)
+    {
+        //printf("TupleExp::inlineScan()\n");
+        inlineScan(&e->e0);
+        arrayInlineScan(e->exps);
+    }
+
+    void visit(ArrayLiteralExp *e)
+    {
+        //printf("ArrayLiteralExp::inlineScan()\n");
+        inlineScan(&e->basis);
+        arrayInlineScan(e->elements);
+    }
+
+    void visit(AssocArrayLiteralExp *e)
+    {
+        //printf("AssocArrayLiteralExp::inlineScan()\n");
+        arrayInlineScan(e->keys);
+        arrayInlineScan(e->values);
+    }
+
+    void visit(StructLiteralExp *e)
+    {
+        //printf("StructLiteralExp::inlineScan()\n");
+        if (e->stageflags & stageInlineScan) return;
+        int old = e->stageflags;
+        e->stageflags |= stageInlineScan;
+        arrayInlineScan(e->elements);
+        e->stageflags = old;
+    }
+
+    void visit(ArrayExp *e)
+    {
+        //printf("ArrayExp::inlineScan()\n");
+        inlineScan(&e->e1);
+        arrayInlineScan(e->arguments);
+    }
+
+    void visit(CondExp *e)
+    {
+        inlineScan(&e->econd);
+        inlineScan(&e->e1);
+        inlineScan(&e->e2);
+    }
+
+    void inlineScan(Expression **e)
+    {
+        if (!*e) return;
+        assert(eresult == NULL);
+        (*e)->accept(this);
+        if (eresult)
+        {
+            *e = eresult;
+            eresult = NULL;
+        }
+    }
+
+    /*************************************
+     * Look for function inlining possibilities.
+     */
+
+    void visit(Dsymbol *d)
+    {
+        // Most Dsymbols aren't functions
+    }
+
+    void visit(FuncDeclaration *fd)
+    {
+    #if LOG
+        printf("FuncDeclaration::inlineScan('%s')\n", fd->toPrettyChars());
+    #endif
+        if (fd->isUnitTestDeclaration() && !global.params.useUnitTests ||
+            fd->flags & FUNCFLAGinlineScanned)
+            return;
+
+        if (fd->fbody && !fd->naked)
+        {
+            bool againsave = again;
+            FuncDeclaration *parentsave = parent;
+            parent = fd;
+            do
+            {
+                again = false;
+                fd->inlineNest++;
+                fd->flags |= FUNCFLAGinlineScanned;
+                inlineScan(&fd->fbody);
+                fd->inlineNest--;
+            }
+            while (again);
+            again = againsave;
+            parent = parentsave;
+        }
+    }
+
+    void visit(AttribDeclaration *d)
+    {
+        Dsymbols *decls = d->include(NULL, NULL);
+
+        if (decls)
+        {
+            for (size_t i = 0; i < decls->dim; i++)
+            {
+                Dsymbol *s = (*decls)[i];
+                //printf("AttribDeclaration::inlineScan %s\n", s->toChars());
+                s->accept(this);
+            }
+        }
+    }
+
+    void visit(AggregateDeclaration *ad)
+    {
+        //printf("AggregateDeclaration::inlineScan(%s)\n", toChars());
+        if (ad->members)
+        {
+            for (size_t i = 0; i < ad->members->dim; i++)
+            {
+                Dsymbol *s = (*ad->members)[i];
+                //printf("inline scan aggregate symbol '%s'\n", s->toChars());
+                s->accept(this);
+            }
+        }
+    }
+
+    void visit(TemplateInstance *ti)
+    {
+    #if LOG
+        printf("TemplateInstance::inlineScan('%s')\n", ti->toChars());
+    #endif
+        if (!ti->errors && ti->members)
+        {
+            for (size_t i = 0; i < ti->members->dim; i++)
+            {
+                Dsymbol *s = (*ti->members)[i];
+                s->accept(this);
+            }
+        }
+    }
+};
+
+// scan for functions to inline
+void inlineScan(Module *m)
+{
+    if (m->semanticRun != PASSsemantic3done)
+        return;
+    m->semanticRun = PASSinline;
+
+    // Note that modules get their own scope, from scratch.
+    // This is so regardless of where in the syntax a module
+    // gets imported, it is unaffected by context.
+    //printf("Module = %p\n", m->sc.scopesym);
+
+    for (size_t i = 0; i < m->members->dim; i++)
+    {
+        Dsymbol *s = (*m->members)[i];
+        //if (global.params.verbose)
+        //    fprintf(global.stdmsg, "inline scan symbol %s\n", s->toChars());
+        InlineScanVisitor v;
+        s->accept(&v);
+    }
+    m->semanticRun = PASSinlinedone;
+}
+
+bool canInline(FuncDeclaration *fd, int hasthis, int hdrscan, bool statementsToo)
+{
+    int cost;
+
+#define CANINLINE_LOG 0
+
+#if CANINLINE_LOG
+    printf("FuncDeclaration::canInline(hasthis = %d, statementsToo = %d, '%s')\n", hasthis, statementsToo, fd->toPrettyChars());
+#endif
+
+    if (fd->needThis() && !hasthis)
+        return false;
+
+    if (fd->inlineNest)
+    {
+#if CANINLINE_LOG
+        printf("\t1: no, inlineNest = %d, semanticRun = %d\n", fd->inlineNest, fd->semanticRun);
+#endif
+        return false;
+    }
+
+    if (fd->semanticRun < PASSsemantic3 && !hdrscan)
+    {
+        if (!fd->fbody)
+            return false;
+        if (!fd->functionSemantic3())
+            return false;
+        Module::runDeferredSemantic3();
+        if (global.errors)
+            return false;
+        assert(fd->semanticRun >= PASSsemantic3done);
+    }
+
+    switch (statementsToo ? fd->inlineStatusStmt : fd->inlineStatusExp)
+    {
+        case ILSyes:
+#if CANINLINE_LOG
+            printf("\t1: yes %s\n", fd->toChars());
+#endif
+            return true;
+
+        case ILSno:
+#if CANINLINE_LOG
+            printf("\t1: no %s\n", fd->toChars());
+#endif
+            return false;
+
+        case ILSuninitialized:
+            break;
+
+        default:
+            assert(0);
+    }
+
+    switch (fd->inlining)
+    {
+        case PINLINEdefault:
+            break;
+
+        case PINLINEalways:
+            break;
+
+        case PINLINEnever:
+            return false;
+        default:
+            assert(0);
+    }
+
+    if (fd->type)
+    {
+        assert(fd->type->ty == Tfunction);
+        TypeFunction *tf = (TypeFunction *)fd->type;
+        if (tf->varargs == 1)   // no variadic parameter lists
+            goto Lno;
+
+        /* Don't inline a function that returns non-void, but has
+         * no or multiple return expression.
+         * No statement inlining for non-voids.
+         */
+        if (tf->next && tf->next->ty != Tvoid &&
+            (!(fd->hasReturnExp & 1) || statementsToo) &&
+            !hdrscan)
+            goto Lno;
+
+        /* Bugzilla 14560: If fd returns void, all explicit `return;`s
+         * must not appear in the expanded result.
+         * See also ReturnStatement::inlineAsStatement().
+         */
+    }
+
+    // cannot inline constructor calls because we need to convert:
+    //      return;
+    // to:
+    //      return this;
+    // ensure() has magic properties the inliner loses
+    // require() has magic properties too
+    // see bug 7699
+    // no nested references to this frame
+    if (!fd->fbody ||
+        fd->ident == Id::ensure ||
+        (fd->ident == Id::require &&
+         fd->toParent()->isFuncDeclaration() &&
+         fd->toParent()->isFuncDeclaration()->needThis()) ||
+        !hdrscan &&
+        (
+        fd->isSynchronized() ||
+        fd->isImportedSymbol() ||
+        fd->hasNestedFrameRefs() ||
+        (fd->isVirtual() && !fd->isFinalFunc())
+       ))
+    {
+        goto Lno;
+    }
+
+    // cannot inline functions as statement if they have multiple
+    //  return statements
+    if ((fd->hasReturnExp & 16) && statementsToo)
+    {
+#if CANINLINE_LOG
+        printf("\t5: no %s\n", fd->toChars());
+#endif
+        goto Lno;
+    }
+
+    {
+        cost = inlineCostFunction(fd, hasthis, hdrscan);
+    }
+#if CANINLINE_LOG
+    printf("\tcost = %d for %s\n", cost, fd->toChars());
+#endif
+    if (tooCostly(cost))
+        goto Lno;
+    if (!statementsToo && cost > COST_MAX)
+        goto Lno;
+
+    if (!hdrscan)
+    {
+        // Don't modify inlineStatus for header content scan
+        if (statementsToo)
+            fd->inlineStatusStmt = ILSyes;
+        else
+            fd->inlineStatusExp = ILSyes;
+
+        InlineScanVisitor v;
+        fd->accept(&v);      // Don't scan recursively for header content scan
+
+        if (fd->inlineStatusExp == ILSuninitialized)
+        {
+            // Need to redo cost computation, as some statements or expressions have been inlined
+            cost = inlineCostFunction(fd, hasthis, hdrscan);
+        #if CANINLINE_LOG
+            printf("recomputed cost = %d for %s\n", cost, fd->toChars());
+        #endif
+            if (tooCostly(cost))
+                goto Lno;
+            if (!statementsToo && cost > COST_MAX)
+                goto Lno;
+
+            if (statementsToo)
+                fd->inlineStatusStmt = ILSyes;
+            else
+                fd->inlineStatusExp = ILSyes;
+        }
+    }
+#if CANINLINE_LOG
+    printf("\t2: yes %s\n", fd->toChars());
+#endif
+    return true;
+
+Lno:
+    if (fd->inlining == PINLINEalways)
+        fd->error("cannot inline function");
+
+    if (!hdrscan)    // Don't modify inlineStatus for header content scan
+    {
+        if (statementsToo)
+            fd->inlineStatusStmt = ILSno;
+        else
+            fd->inlineStatusExp = ILSno;
+    }
+#if CANINLINE_LOG
+    printf("\t2: no %s\n", fd->toChars());
+#endif
+    return false;
+}
+
+/***********************************************************
+ * Expand a function call inline,
+ *      ethis.fd(arguments)
+ *
+ * Params:
+ *      callLoc = location of CallExp
+ *      fd = function to expand
+ *      parent = function that the call to fd is being expanded into
+ *      eret = expression describing the lvalue of where the return value goes
+ *      ethis = 'this' reference
+ *      arguments = arguments passed to fd
+ *      asStatements = expand to Statements rather than Expressions
+ *      eresult = if expanding to an expression, this is where the expression is written to
+ *      sresult = if expanding to a statement, this is where the statement is written to
+ *      again = if true, then fd can be inline scanned again because there may be
+ *           more opportunities for inlining
+ */
+static void expandInline(Loc callLoc, FuncDeclaration *fd, FuncDeclaration *parent,
+        Expression *eret, Expression *ethis, Expressions *arguments, bool asStatements,
+        Expression **eresult, Statement **sresult, bool *again)
+{
+    InlineDoState ids;
+    TypeFunction *tf = (TypeFunction*)fd->type;
+
+#define EXPANDINLINE_LOG 0
+
+#if LOG || CANINLINE_LOG || EXPANDINLINE_LOG
+    printf("FuncDeclaration::expandInline('%s')\n", fd->toChars());
+#endif
+#if EXPANDINLINE_LOG
+    if (eret) printf("\teret = %s\n", eret->toChars());
+    if (ethis) printf("\tethis = %s\n", ethis->toChars());
+#endif
+
+    memset(&ids, 0, sizeof(ids));
+    ids.parent = parent;
+    ids.fd = fd;
+
+    if (fd->isNested())
+    {
+        if (!parent->inlinedNestedCallees)
+            parent->inlinedNestedCallees = new FuncDeclarations();
+        parent->inlinedNestedCallees->push(fd);
+    }
+
+    VarDeclaration *vret = NULL;    // will be set the function call result
+    if (eret)
+    {
+        if (eret->op == TOKvar)
+        {
+            vret = ((VarExp *)eret)->var->isVarDeclaration();
+            assert(!(vret->storage_class & (STCout | STCref)));
+            eret = NULL;
+        }
+        else
+        {
+            /* Inlining:
+             *   this.field = foo();   // inside constructor
+             */
+            ExpInitializer *ei = new ExpInitializer(callLoc, NULL);
+            Identifier *tmp = Identifier::generateId("__retvar");
+            vret = new VarDeclaration(fd->loc, eret->type, tmp, ei);
+            vret->storage_class |= STCtemp | STCref;
+            vret->linkage = LINKd;
+            vret->parent = parent;
+
+            ei->exp = new ConstructExp(fd->loc, vret, eret);
+            ei->exp->type = vret->type;
+
+            Expression *de = new DeclarationExp(fd->loc, vret);
+            de->type = Type::tvoid;
+            eret = de;
+        }
+
+        if (!asStatements && fd->nrvo_var)
+        {
+            ids.from.push(fd->nrvo_var);
+            ids.to.push(vret);
+        }
+    }
+    else
+    {
+        if (!asStatements && fd->nrvo_var)
+        {
+            Identifier *tmp = Identifier::generateId("__retvar");
+            vret = new VarDeclaration(fd->loc, fd->nrvo_var->type, tmp, NULL);
+            assert(!tf->isref);
+            vret->storage_class = STCtemp | STCrvalue;
+            vret->linkage = tf->linkage;
+            vret->parent = parent;
+
+            DeclarationExp *de = new DeclarationExp(fd->loc, vret);
+            de->type = Type::tvoid;
+            eret = de;
+
+            ids.from.push(fd->nrvo_var);
+            ids.to.push(vret);
+        }
+    }
+
+    // Set up vthis
+    VarDeclaration *vthis = NULL;
+    if (ethis)
+    {
+        Expression *e0 = NULL;
+        ethis = Expression::extractLast(ethis, &e0);
+        if (ethis->op == TOKvar)
+        {
+            vthis = ((VarExp *)ethis)->var->isVarDeclaration();
+        }
+        else
+        {
+            //assert(ethis->type->ty != Tpointer)
+            if (ethis->type->ty == Tpointer)
+            {
+                Type *t = ethis->type->nextOf();
+                ethis = new PtrExp(ethis->loc, ethis);
+                ethis->type = t;
+            }
+
+            ExpInitializer *ei = new ExpInitializer(fd->loc, ethis);
+            vthis = new VarDeclaration(fd->loc, ethis->type, Id::This, ei);
+            if (ethis->type->ty != Tclass)
+                vthis->storage_class = STCref;
+            else
+                vthis->storage_class = STCin;
+            vthis->linkage = LINKd;
+            vthis->parent = parent;
+
+            ei->exp = new ConstructExp(fd->loc, vthis, ethis);
+            ei->exp->type = vthis->type;
+
+            Expression *de = new DeclarationExp(fd->loc, vthis);
+            de->type = Type::tvoid;
+            e0 = Expression::combine(e0, de);
+        }
+        ethis = e0;
+
+        ids.vthis = vthis;
+    }
+
+    // Set up parameters
+    Expression *eparams = NULL;
+    if (arguments && arguments->dim)
+    {
+        assert(fd->parameters->dim == arguments->dim);
+
+        for (size_t i = 0; i < arguments->dim; i++)
+        {
+            VarDeclaration *vfrom = (*fd->parameters)[i];
+            Expression *arg = (*arguments)[i];
+
+            ExpInitializer *ei = new ExpInitializer(vfrom->loc, arg);
+            VarDeclaration *vto = new VarDeclaration(vfrom->loc, vfrom->type, vfrom->ident, ei);
+            vto->storage_class |= vfrom->storage_class & (STCtemp | STCin | STCout | STClazy | STCref);
+            vto->linkage = vfrom->linkage;
+            vto->parent = parent;
+            //printf("vto = '%s', vto->storage_class = x%x\n", vto->toChars(), vto->storage_class);
+            //printf("vto->parent = '%s'\n", parent->toChars());
+
+            // Even if vto is STClazy, `vto = arg` is handled correctly in glue layer.
+            ei->exp = new BlitExp(vto->loc, vto, arg);
+            ei->exp->type = vto->type;
+            //arg->type->print();
+            //ei->exp->print();
+
+            ids.from.push(vfrom);
+            ids.to.push(vto);
+
+            DeclarationExp *de = new DeclarationExp(vto->loc, vto);
+            de->type = Type::tvoid;
+
+            eparams = Expression::combine(eparams, de);
+
+            /* If function pointer or delegate parameters are present,
+             * inline scan again because if they are initialized to a symbol,
+             * any calls to the fp or dg can be inlined.
+             */
+            if (vfrom->type->ty == Tdelegate ||
+                vfrom->type->ty == Tpointer && vfrom->type->nextOf()->ty == Tfunction)
+            {
+                if (arg->op == TOKvar)
+                {
+                    VarExp *ve = (VarExp *)arg;
+                    if (ve->var->isFuncDeclaration())
+                        *again = true;
+                }
+                else if (arg->op == TOKsymoff)
+                {
+                    SymOffExp *se = (SymOffExp *)arg;
+                    if (se->var->isFuncDeclaration())
+                        *again = true;
+                }
+                else if (arg->op == TOKfunction || arg->op == TOKdelegate)
+                    *again = true;
+            }
+        }
+    }
+
+    if (asStatements)
+    {
+        /* Construct:
+         *  { eret; ethis; eparams; fd.fbody; }
+         * or:
+         *  { eret; ethis; try { eparams; fd.fbody; } finally { vthis.edtor; } }
+         */
+
+        Statements *as = new Statements();
+        if (eret)
+            as->push(new ExpStatement(callLoc, eret));
+        if (ethis)
+            as->push(new ExpStatement(callLoc, ethis));
+
+        Statements *as2 = as;
+        if (vthis && !vthis->isDataseg())
+        {
+            if (vthis->needsScopeDtor())
+            {
+                // same with ExpStatement::scopeCode()
+                as2 = new Statements();
+                vthis->storage_class |= STCnodtor;
+            }
+        }
+
+        if (eparams)
+            as2->push(new ExpStatement(callLoc, eparams));
+
+        if (as2 != as)
+        {
+            as->push(new TryFinallyStatement(callLoc,
+                        new CompoundStatement(callLoc, as2),
+                        new DtorExpStatement(callLoc, vthis->edtor, vthis)));
+
+        }
+
+        fd->inlineNest++;
+        Statement *s = inlineAsStatement(fd->fbody, &ids);
+        fd->inlineNest--;
+        as->push(s);
+
+        *sresult = new ScopeStatement(callLoc, new CompoundStatement(Loc(), as), Loc());
+
+#if EXPANDINLINE_LOG
+        printf("\n[%s] %s expandInline sresult =\n%s\n",
+            callLoc.toChars(), fd->toPrettyChars(), (*sresult)->toChars());
+#endif
+    }
+    else
+    {
+        /* Construct:
+         *  (eret, ethis, eparams, fd.fbody)
+         */
+
+        fd->inlineNest++;
+        Expression *e = doInline(fd->fbody, &ids);
+        fd->inlineNest--;
+        //e->type->print();
+        //e->print();
+        //e->print();
+
+        // Bugzilla 11322:
+        if (tf->isref)
+            e = e->toLvalue(NULL, NULL);
+
+        /* There's a problem if what the function returns is used subsequently as an
+         * lvalue, as in a struct return that is then used as a 'this'.
+         * If we take the address of the return value, we will be taking the address
+         * of the original, not the copy. Fix this by assigning the return value to
+         * a temporary, then returning the temporary. If the temporary is used as an
+         * lvalue, it will work.
+         * This only happens with struct returns.
+         * See Bugzilla 2127 for an example.
+         *
+         * On constructor call making __inlineretval is merely redundant, because
+         * the returned reference is exactly same as vthis, and the 'this' variable
+         * already exists at the caller side.
+         */
+        if (tf->next->ty == Tstruct && !fd->nrvo_var && !fd->isCtorDeclaration())
+        {
+            /* Generate a new variable to hold the result and initialize it with the
+             * inlined body of the function:
+             *   tret __inlineretval = e;
+             */
+            ExpInitializer* ei = new ExpInitializer(callLoc, e);
+            Identifier* tmp = Identifier::generateId("__inlineretval");
+            VarDeclaration* vd = new VarDeclaration(callLoc, tf->next, tmp, ei);
+            vd->storage_class = STCtemp | (tf->isref ? STCref : STCrvalue);
+            vd->linkage = tf->linkage;
+            vd->parent = parent;
+
+            ei->exp = new ConstructExp(callLoc, vd, e);
+            ei->exp->type = vd->type;
+
+            DeclarationExp* de = new DeclarationExp(callLoc, vd);
+            de->type = Type::tvoid;
+
+            // Chain the two together:
+            //   ( typeof(return) __inlineretval = ( inlined body )) , __inlineretval
+            e = Expression::combine(de, new VarExp(callLoc, vd));
+
+            //fprintf(stderr, "CallExp::inlineScan: e = "); e->print();
+        }
+
+        // Bugzilla 15210
+        if (tf->next->ty == Tvoid && e && e->type->ty != Tvoid)
+        {
+            e = new CastExp(callLoc, e, Type::tvoid);
+            e->type = Type::tvoid;
+        }
+
+        *eresult = Expression::combine(*eresult, eret);
+        *eresult = Expression::combine(*eresult, ethis);
+        *eresult = Expression::combine(*eresult, eparams);
+        *eresult = Expression::combine(*eresult, e);
+
+#if EXPANDINLINE_LOG
+        printf("\n[%s] %s expandInline eresult = %s\n",
+            callLoc.toChars(), fd->toPrettyChars(), (*eresult)->toChars());
+#endif
+    }
+
+    // Need to reevaluate whether parent can now be inlined
+    // in expressions, as we might have inlined statements
+    parent->inlineStatusExp = ILSuninitialized;
+}
+
+/****************************************************
+ * Perform the "inline copying" of a default argument for a function parameter.
+ */
+
+Expression *inlineCopy(Expression *e, Scope *sc)
+{
+    /* See Bugzilla 2935 for explanation of why just a copy() is broken
+     */
+    //return e->copy();
+
+    if (e->op == TOKdelegate)
+    {
+        DelegateExp *de = (DelegateExp *)e;
+
+        if (de->func->isNested())
+        {
+            /* See Bugzilla 4820
+             * Defer checking until later if we actually need the 'this' pointer
+             */
+            return de->copy();
+        }
+    }
+
+    int cost = inlineCostExpression(e);
+    if (cost >= COST_MAX)
+    {
+        e->error("cannot inline default argument %s", e->toChars());
+        return new ErrorExp();
+    }
+    InlineDoState ids;
+    memset(&ids, 0, sizeof(ids));
+    ids.parent = sc->parent;
+    return doInline(e, &ids);
+}
+
diff --git a/gcc/d/dfrontend/inlinecost.c b/gcc/d/dfrontend/inlinecost.c
new file mode 100644
index 00000000000..c1d165a32be
--- /dev/null
+++ b/gcc/d/dfrontend/inlinecost.c
@@ -0,0 +1,421 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/inlinecost.c
+ */
+
+#include "id.h"
+#include "init.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "statement.h"
+#include "tokens.h"
+
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+
+const int COST_MAX = 250;
+const int STATEMENT_COST = 0x1000;
+const int STATEMENT_COST_MAX = 250 * STATEMENT_COST;
+
+// STATEMENT_COST be power of 2 and greater than COST_MAX
+//static assert((STATEMENT_COST & (STATEMENT_COST - 1)) == 0);
+//static assert(STATEMENT_COST > COST_MAX);
+
+/*********************************
+ * Determine if too expensive to inline.
+ * Params:
+ *      cost = cost of inlining
+ * Returns:
+ *      true if too costly
+ */
+bool tooCostly(int cost)
+{
+    return ((cost & (STATEMENT_COST - 1)) >= COST_MAX);
+}
+
+/* ========== Compute cost of inlining =============== */
+
+/* Walk trees to determine if inlining can be done, and if so,
+ * if it is too complex to be worth inlining or not.
+ */
+
+class InlineCostVisitor : public Visitor
+{
+public:
+    int nested;
+    int hasthis;
+    int hdrscan;    // !=0 if inline scan for 'header' content
+    bool allowAlloca;
+    FuncDeclaration *fd;
+    int cost;
+
+    InlineCostVisitor()
+    {
+        nested = 0;
+        hasthis = 0;
+        hdrscan = 0;
+        allowAlloca = false;
+        fd = NULL;
+        cost = 0;
+    }
+
+    InlineCostVisitor(bool hasthis, bool hdrscan, bool allowAlloca, FuncDeclaration *fd)
+    {
+        this->nested = 0;
+        this->hasthis = hasthis;
+        this->hdrscan = hdrscan;
+        this->allowAlloca = allowAlloca;
+        this->fd = fd;
+        this->cost = 0;
+    }
+
+    InlineCostVisitor(InlineCostVisitor *icv)
+    {
+        nested = icv->nested;
+        hasthis = icv->hasthis;
+        hdrscan = icv->hdrscan;
+        allowAlloca = icv->allowAlloca;
+        fd = icv->fd;
+        cost = 0;   // zero start for subsequent AST
+    }
+
+    void visit(Statement *s)
+    {
+        //printf("Statement::inlineCost = %d\n", COST_MAX);
+        //printf("%p\n", s->isScopeStatement());
+        //printf("%s\n", s->toChars());
+        cost += COST_MAX;            // default is we can't inline it
+    }
+
+    void visit(ExpStatement *s)
+    {
+        expressionInlineCost(s->exp);
+    }
+
+    void visit(CompoundStatement *s)
+    {
+        InlineCostVisitor icv(this);
+        for (size_t i = 0; i < s->statements->dim; i++)
+        {
+            Statement *s2 = (*s->statements)[i];
+            if (s2)
+            {
+                s2->accept(&icv);
+                if (tooCostly(icv.cost))
+                    break;
+            }
+        }
+        cost += icv.cost;
+    }
+
+    void visit(UnrolledLoopStatement *s)
+    {
+        InlineCostVisitor icv(this);
+        for (size_t i = 0; i < s->statements->dim; i++)
+        {
+            Statement *s2 = (*s->statements)[i];
+            if (s2)
+            {
+                s2->accept(&icv);
+                if (tooCostly(icv.cost))
+                    break;
+            }
+        }
+        cost += icv.cost;
+    }
+
+    void visit(ScopeStatement *s)
+    {
+        cost++;
+        if (s->statement)
+            s->statement->accept(this);
+    }
+
+    void visit(IfStatement *s)
+    {
+        /* Can't declare variables inside ?: expressions, so
+         * we cannot inline if a variable is declared.
+         */
+        if (s->prm)
+        {
+            cost = COST_MAX;
+            return;
+        }
+
+        expressionInlineCost(s->condition);
+
+        /* Specifically allow:
+         *  if (condition)
+         *      return exp1;
+         *  else
+         *      return exp2;
+         * Otherwise, we can't handle return statements nested in if's.
+         */
+
+        if (s->elsebody && s->ifbody &&
+            s->ifbody->isReturnStatement() &&
+            s->elsebody->isReturnStatement())
+        {
+            s->ifbody->accept(this);
+            s->elsebody->accept(this);
+            //printf("cost = %d\n", cost);
+        }
+        else
+        {
+            nested += 1;
+            if (s->ifbody)
+                s->ifbody->accept(this);
+            if (s->elsebody)
+                s->elsebody->accept(this);
+            nested -= 1;
+        }
+        //printf("IfStatement::inlineCost = %d\n", cost);
+    }
+
+    void visit(ReturnStatement *s)
+    {
+        // Can't handle return statements nested in if's
+        if (nested)
+        {
+            cost = COST_MAX;
+        }
+        else
+        {
+            expressionInlineCost(s->exp);
+        }
+    }
+
+    void visit(ImportStatement *s)
+    {
+    }
+
+    void visit(ForStatement *s)
+    {
+        cost += STATEMENT_COST;
+        if (s->_init)
+            s->_init->accept(this);
+        if (s->condition)
+            s->condition->accept(this);
+        if (s->increment)
+            s->increment->accept(this);
+        if (s->_body)
+            s->_body->accept(this);
+        //printf("ForStatement: inlineCost = %d\n", cost);
+    }
+
+    void visit(ThrowStatement *s)
+    {
+        cost += STATEMENT_COST;
+        s->exp->accept(this);
+    }
+
+    /* -------------------------- */
+
+    void expressionInlineCost(Expression *e)
+    {
+        //printf("expressionInlineCost()\n");
+        //e->print();
+        if (e)
+        {
+            class LambdaInlineCost : public StoppableVisitor
+            {
+                InlineCostVisitor *icv;
+            public:
+                LambdaInlineCost(InlineCostVisitor *icv) : icv(icv) {}
+
+                void visit(Expression *e)
+                {
+                    e->accept(icv);
+                    stop = icv->cost >= COST_MAX;
+                }
+            };
+
+            InlineCostVisitor icv(this);
+            LambdaInlineCost lic(&icv);
+            walkPostorder(e, &lic);
+            cost += icv.cost;
+        }
+    }
+
+    void visit(Expression *e)
+    {
+        cost++;
+    }
+
+    void visit(VarExp *e)
+    {
+        //printf("VarExp::inlineCost3() %s\n", toChars());
+        Type *tb = e->type->toBasetype();
+        if (tb->ty == Tstruct)
+        {
+            StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+            if (sd->isNested())
+            {
+                /* An inner struct will be nested inside another function hierarchy than where
+                 * we're inlining into, so don't inline it.
+                 * At least not until we figure out how to 'move' the struct to be nested
+                 * locally. Example:
+                 *   struct S(alias pred) { void unused_func(); }
+                 *   void abc() { int w; S!(w) m; }
+                 *   void bar() { abc(); }
+                 */
+                cost = COST_MAX;
+                return;
+            }
+        }
+        FuncDeclaration *fd = e->var->isFuncDeclaration();
+        if (fd && fd->isNested())           // see Bugzilla 7199 for test case
+            cost = COST_MAX;
+        else
+            cost++;
+    }
+
+    void visit(ThisExp *e)
+    {
+        //printf("ThisExp::inlineCost3() %s\n", toChars());
+        if (!fd)
+        {
+            cost = COST_MAX;
+            return;
+        }
+        if (!hdrscan)
+        {
+            if (fd->isNested() || !hasthis)
+            {
+                cost = COST_MAX;
+                return;
+            }
+        }
+        cost++;
+    }
+
+    void visit(StructLiteralExp *e)
+    {
+        //printf("StructLiteralExp::inlineCost3() %s\n", toChars());
+        if (e->sd->isNested())
+            cost = COST_MAX;
+        else
+            cost++;
+    }
+
+    void visit(NewExp *e)
+    {
+        //printf("NewExp::inlineCost3() %s\n", e->toChars());
+        AggregateDeclaration *ad = isAggregate(e->newtype);
+        if (ad && ad->isNested())
+            cost = COST_MAX;
+        else
+            cost++;
+    }
+
+    void visit(FuncExp *e)
+    {
+        //printf("FuncExp::inlineCost3()\n");
+        // Right now, this makes the function be output to the .obj file twice.
+        cost = COST_MAX;
+    }
+
+    void visit(DelegateExp *e)
+    {
+        //printf("DelegateExp::inlineCost3()\n");
+        cost = COST_MAX;
+    }
+
+    void visit(DeclarationExp *e)
+    {
+        //printf("DeclarationExp::inlineCost3()\n");
+        VarDeclaration *vd = e->declaration->isVarDeclaration();
+        if (vd)
+        {
+            TupleDeclaration *td = vd->toAlias()->isTupleDeclaration();
+            if (td)
+            {
+                cost = COST_MAX;    // finish DeclarationExp::doInline
+                return;
+            }
+            if (!hdrscan && vd->isDataseg())
+            {
+                cost = COST_MAX;
+                return;
+            }
+
+            if (vd->edtor)
+            {
+                // if destructor required
+                // needs work to make this work
+                cost = COST_MAX;
+                return;
+            }
+            // Scan initializer (vd->init)
+            if (vd->_init)
+            {
+                ExpInitializer *ie = vd->_init->isExpInitializer();
+
+                if (ie)
+                {
+                    expressionInlineCost(ie->exp);
+                }
+            }
+            cost += 1;
+        }
+
+        // These can contain functions, which when copied, get output twice.
+        if (e->declaration->isStructDeclaration() ||
+            e->declaration->isClassDeclaration() ||
+            e->declaration->isFuncDeclaration() ||
+            e->declaration->isAttribDeclaration() ||
+            e->declaration->isTemplateMixin())
+        {
+            cost = COST_MAX;
+            return;
+        }
+
+        //printf("DeclarationExp::inlineCost3('%s')\n", toChars());
+    }
+
+    void visit(CallExp *e)
+    {
+        //printf("CallExp::inlineCost3() %s\n", toChars());
+        // Bugzilla 3500: super.func() calls must be devirtualized, and the inliner
+        // can't handle that at present.
+        if (e->e1->op == TOKdotvar && ((DotVarExp *)e->e1)->e1->op == TOKsuper)
+            cost = COST_MAX;
+        else if (e->f && e->f->ident == Id::__alloca && e->f->linkage == LINKc && !allowAlloca)
+            cost = COST_MAX; // inlining alloca may cause stack overflows
+        else
+            cost++;
+    }
+};
+
+/*********************************
+ * Determine cost of inlining Expression
+ * Params:
+ *      e = Expression to determine cost of
+ * Returns:
+ *      cost of inlining e
+ */
+int inlineCostExpression(Expression *e)
+{
+    InlineCostVisitor icv = InlineCostVisitor(false, true, true, NULL);
+    icv.expressionInlineCost(e);
+    return icv.cost;
+}
+
+/*********************************
+ * Determine cost of inlining function
+ * Params:
+ *      fd = function to determine cost of
+ * Returns:
+ *      cost of inlining fd
+ */
+int inlineCostFunction(FuncDeclaration *fd, bool hasthis, bool hdrscan)
+{
+    InlineCostVisitor icv = InlineCostVisitor(hasthis, hdrscan, false, fd);
+    fd->fbody->accept(&icv);
+    return icv.cost;
+}
diff --git a/gcc/d/dfrontend/intrange.c b/gcc/d/dfrontend/intrange.c
new file mode 100644
index 00000000000..db590b5bc43
--- /dev/null
+++ b/gcc/d/dfrontend/intrange.c
@@ -0,0 +1,1107 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by KennyTM
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/intrange.c
+ */
+
+#include "intrange.h"
+#include "mars.h"
+#include "mtype.h"
+#include "expression.h"
+
+#ifndef PERFORM_UNITTEST
+#define PERFORM_UNITTEST 0
+#endif
+
+// Copy the sign to the value *x*. Equivalent to `sign ? -x : x`.
+static uinteger_t copySign(uinteger_t x, bool sign)
+{
+    // return sign ? -x : x;
+    return (x - (uinteger_t)sign) ^ -(uinteger_t)sign;
+}
+
+#ifndef UINT64_MAX
+#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
+#endif
+
+//==================== SignExtendedNumber ======================================
+
+SignExtendedNumber SignExtendedNumber::fromInteger(uinteger_t value_)
+{
+    return SignExtendedNumber(value_, value_ >> 63);
+}
+
+bool SignExtendedNumber::operator==(const SignExtendedNumber& a) const
+{
+    return value == a.value && negative == a.negative;
+}
+
+bool SignExtendedNumber::operator<(const SignExtendedNumber& a) const
+{
+    return (negative && !a.negative)
+        || (negative == a.negative && value < a.value);
+}
+
+SignExtendedNumber SignExtendedNumber::extreme(bool minimum)
+{
+    return SignExtendedNumber(minimum-1, minimum);
+}
+
+SignExtendedNumber SignExtendedNumber::max()
+{
+    return SignExtendedNumber(UINT64_MAX, false);
+}
+
+SignExtendedNumber SignExtendedNumber::operator-() const
+{
+    if (value == 0)
+        return SignExtendedNumber(-negative);
+    else
+        return SignExtendedNumber(-value, !negative);
+}
+
+SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) const
+{
+    uinteger_t sum = value + a.value;
+    bool carry = sum < value && sum < a.value;
+    if (negative != a.negative)
+        return SignExtendedNumber(sum, !carry);
+    else if (negative)
+        return SignExtendedNumber(carry ? sum : 0, true);
+    else
+        return SignExtendedNumber(carry ? UINT64_MAX : sum, false);
+}
+
+SignExtendedNumber SignExtendedNumber::operator-(const SignExtendedNumber& a) const
+{
+    if (a.isMinimum())
+        return negative ? SignExtendedNumber(value, false) : max();
+    else
+        return *this + (-a);
+}
+
+
+SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) const
+{
+    // perform *saturated* multiplication, otherwise we may get bogus ranges
+    //  like 0x10 * 0x10 == 0x100 == 0.
+
+    /* Special handling for zeros:
+        INT65_MIN * 0 = 0
+        INT65_MIN * + = INT65_MIN
+        INT65_MIN * - = INT65_MAX
+        0 * anything = 0
+    */
+    if (value == 0)
+    {
+        if (!negative)
+            return *this;
+        else if (a.negative)
+            return max();
+        else
+            return a.value == 0 ? a : *this;
+    }
+    else if (a.value == 0)
+        return a * *this;   // don't duplicate the symmetric case.
+
+    SignExtendedNumber rv;
+    // these are != 0 now surely.
+    uinteger_t tAbs = copySign(value, negative);
+    uinteger_t aAbs = copySign(a.value, a.negative);
+    rv.negative = negative != a.negative;
+    if (UINT64_MAX / tAbs < aAbs)
+        rv.value = rv.negative-1;
+    else
+        rv.value = copySign(tAbs * aAbs, rv.negative);
+    return rv;
+}
+
+SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) const
+{
+    /* special handling for zeros:
+        INT65_MIN / INT65_MIN = 1
+        anything / INT65_MIN = 0
+        + / 0 = INT65_MAX  (eh?)
+        - / 0 = INT65_MIN  (eh?)
+    */
+    if (a.value == 0)
+    {
+        if (a.negative)
+            return SignExtendedNumber(value == 0 && negative);
+        else
+            return extreme(negative);
+    }
+
+    uinteger_t aAbs = copySign(a.value, a.negative);
+    uinteger_t rvVal;
+
+    if (!isMinimum())
+        rvVal = copySign(value, negative) / aAbs;
+    // Special handling for INT65_MIN
+    //  if the denominator is not a power of 2, it is same as UINT64_MAX / x.
+    else if (aAbs & (aAbs-1))
+        rvVal = UINT64_MAX / aAbs;
+    // otherwise, it's the same as reversing the bits of x.
+    else
+    {
+        if (aAbs == 1)
+            return extreme(!a.negative);
+        rvVal = 1ULL << 63;
+        aAbs >>= 1;
+        if (aAbs & 0xAAAAAAAAAAAAAAAAULL) rvVal >>= 1;
+        if (aAbs & 0xCCCCCCCCCCCCCCCCULL) rvVal >>= 2;
+        if (aAbs & 0xF0F0F0F0F0F0F0F0ULL) rvVal >>= 4;
+        if (aAbs & 0xFF00FF00FF00FF00ULL) rvVal >>= 8;
+        if (aAbs & 0xFFFF0000FFFF0000ULL) rvVal >>= 16;
+        if (aAbs & 0xFFFFFFFF00000000ULL) rvVal >>= 32;
+    }
+    bool rvNeg = negative != a.negative;
+    rvVal = copySign(rvVal, rvNeg);
+
+    return SignExtendedNumber(rvVal, rvVal != 0 && rvNeg);
+}
+
+SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) const
+{
+    if (a.value == 0)
+        return !a.negative ? a : isMinimum() ? SignExtendedNumber(0) : *this;
+
+    uinteger_t aAbs = copySign(a.value, a.negative);
+    uinteger_t rvVal;
+
+    // a % b == sgn(a) * abs(a) % abs(b).
+    if (!isMinimum())
+        rvVal = copySign(value, negative) % aAbs;
+    // Special handling for INT65_MIN
+    //  if the denominator is not a power of 2, it is same as UINT64_MAX%x + 1.
+    else if (aAbs & (aAbs - 1))
+        rvVal = UINT64_MAX % aAbs + 1;
+    //  otherwise, the modulus is trivially zero.
+    else
+        rvVal = 0;
+
+    rvVal = copySign(rvVal, negative);
+    return SignExtendedNumber(rvVal, rvVal != 0 && negative);
+}
+
+SignExtendedNumber& SignExtendedNumber::operator++()
+{
+    if (value != UINT64_MAX)
+        ++ value;
+    else if (negative)
+    {
+        value = 0;
+        negative = false;
+    }
+    return *this;
+}
+
+SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) const
+{
+    // assume left-shift the shift-amount is always unsigned. Thus negative
+    //  shifts will give huge result.
+    if (value == 0)
+        return *this;
+    else if (a.negative)
+        return extreme(negative);
+
+    uinteger_t v = copySign(value, negative);
+
+    // compute base-2 log of 'v' to determine the maximum allowed bits to shift.
+    // Ref: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
+
+    // Why is this a size_t? Looks like a bug.
+    size_t r, s;
+
+    r = (v > 0xFFFFFFFFULL) << 5; v >>= r;
+    s = (v > 0xFFFFULL    ) << 4; v >>= s; r |= s;
+    s = (v > 0xFFULL      ) << 3; v >>= s; r |= s;
+    s = (v > 0xFULL       ) << 2; v >>= s; r |= s;
+    s = (v > 0x3ULL       ) << 1; v >>= s; r |= s;
+                                           r |= (v >> 1);
+
+    uinteger_t allowableShift = 63 - r;
+    if (a.value > allowableShift)
+        return extreme(negative);
+    else
+        return SignExtendedNumber(value << a.value, negative);
+}
+
+SignExtendedNumber SignExtendedNumber::operator>>(const SignExtendedNumber& a) const
+{
+    if (a.negative || a.value > 64)
+        return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
+    else if (isMinimum())
+        return a.value == 0 ? *this : SignExtendedNumber(-1ULL << (64-a.value), true);
+
+    uinteger_t x = value ^ -negative;
+    x >>= a.value;
+    return SignExtendedNumber(x ^ -negative, negative);
+}
+
+
+//==================== IntRange ================================================
+
+IntRange IntRange::widest()
+{
+    return IntRange(SignExtendedNumber::min(), SignExtendedNumber::max());
+}
+
+#if !PERFORM_UNITTEST
+IntRange IntRange::fromType(Type *type)
+{
+    return fromType(type, type->isunsigned());
+}
+
+IntRange IntRange::fromType(Type *type, bool isUnsigned)
+{
+    if (!type->isintegral())
+        return widest();
+
+    uinteger_t mask = type->sizemask();
+    SignExtendedNumber lower(0), upper(mask);
+    if (type->toBasetype()->ty == Tdchar)
+        upper.value = 0x10FFFFULL;
+    else if (!isUnsigned)
+    {
+        lower.value = ~(mask >> 1);
+        lower.negative = true;
+        upper.value = (mask >> 1);
+    }
+    return IntRange(lower, upper);
+}
+#endif
+
+IntRange IntRange::fromNumbers2(const SignExtendedNumber numbers[2])
+{
+    if (numbers[0] < numbers[1])
+        return IntRange(numbers[0], numbers[1]);
+    else
+        return IntRange(numbers[1], numbers[0]);
+}
+IntRange IntRange::fromNumbers4(const SignExtendedNumber numbers[4])
+{
+    IntRange ab = fromNumbers2(numbers);
+    IntRange cd = fromNumbers2(numbers + 2);
+    if (cd.imin < ab.imin)
+        ab.imin = cd.imin;
+    if (cd.imax > ab.imax)
+        ab.imax = cd.imax;
+    return ab;
+}
+
+bool IntRange::contains(const IntRange& a) const
+{
+    return imin <= a.imin && imax >= a.imax;
+}
+
+bool IntRange::containsZero() const
+{
+    return (imin.negative && !imax.negative)
+        || (!imin.negative && imin.value == 0);
+}
+
+IntRange& IntRange::castUnsigned(uinteger_t mask)
+{
+    // .... 0x1eff ] [0x1f00 .. 0x1fff] [0 .. 0xff] [0x100 .. 0x1ff] [0x200 ....
+    //
+    // regular unsigned type. We just need to see if ir steps across the
+    //  boundary of validRange. If yes, ir will represent the whole validRange,
+    //  otherwise, we just take the modulus.
+    // e.g. [0x105, 0x107] & 0xff == [5, 7]
+    //      [0x105, 0x207] & 0xff == [0, 0xff]
+    uinteger_t minChunk = imin.value & ~mask;
+    uinteger_t maxChunk = imax.value & ~mask;
+    if (minChunk == maxChunk && imin.negative == imax.negative)
+    {
+        imin.value &= mask;
+        imax.value &= mask;
+    }
+    else
+    {
+        imin.value = 0;
+        imax.value = mask;
+    }
+    imin.negative = imax.negative = false;
+    return *this;
+}
+
+IntRange& IntRange::castSigned(uinteger_t mask)
+{
+    // .... 0x1e7f ] [0x1e80 .. 0x1f7f] [0x1f80 .. 0x7f] [0x80 .. 0x17f] [0x180 ....
+    //
+    // regular signed type. We use a technique similar to the unsigned version,
+    //  but the chunk has to be offset by 1/2 of the range.
+    uinteger_t halfChunkMask = mask >> 1;
+    uinteger_t minHalfChunk = imin.value & ~halfChunkMask;
+    uinteger_t maxHalfChunk = imax.value & ~halfChunkMask;
+    int minHalfChunkNegativity = imin.negative; // 1 = neg, 0 = nonneg, -1 = chunk containing ::max
+    int maxHalfChunkNegativity = imax.negative;
+    if (minHalfChunk & mask)
+    {
+        minHalfChunk += halfChunkMask+1;
+        if (minHalfChunk == 0)
+            -- minHalfChunkNegativity;
+    }
+    if (maxHalfChunk & mask)
+    {
+        maxHalfChunk += halfChunkMask+1;
+        if (maxHalfChunk == 0)
+            -- maxHalfChunkNegativity;
+    }
+    if (minHalfChunk == maxHalfChunk && minHalfChunkNegativity == maxHalfChunkNegativity)
+    {
+        imin.value &= mask;
+        imax.value &= mask;
+        // sign extend if necessary.
+        imin.negative = imin.value & ~halfChunkMask;
+        imax.negative = imax.value & ~halfChunkMask;
+        halfChunkMask += 1;
+        imin.value = (imin.value ^ halfChunkMask) - halfChunkMask;
+        imax.value = (imax.value ^ halfChunkMask) - halfChunkMask;
+    }
+    else
+    {
+        imin = SignExtendedNumber(~halfChunkMask, true);
+        imax = SignExtendedNumber(halfChunkMask, false);
+    }
+    return *this;
+}
+
+IntRange& IntRange::castDchar()
+{
+    // special case for dchar. Casting to dchar means "I'll ignore all
+    //  invalid characters."
+    castUnsigned(0xFFFFFFFFULL);
+    if (imin.value > 0x10FFFFULL)   // ??
+        imin.value = 0x10FFFFULL;   // ??
+    if (imax.value > 0x10FFFFULL)
+        imax.value = 0x10FFFFULL;
+    return *this;
+}
+
+#if !PERFORM_UNITTEST
+IntRange& IntRange::cast(Type *type)
+{
+    if (!type->isintegral())
+        return *this;
+    else if (!type->isunsigned())
+        return castSigned(type->sizemask());
+    else if (type->toBasetype()->ty == Tdchar)
+        return castDchar();
+    else
+        return castUnsigned(type->sizemask());
+}
+
+IntRange& IntRange::castUnsigned(Type *type)
+{
+    if (!type->isintegral())
+        return castUnsigned(UINT64_MAX);
+    else if (type->toBasetype()->ty == Tdchar)
+        return castDchar();
+    else
+        return castUnsigned(type->sizemask());
+}
+#endif
+
+IntRange IntRange::absNeg() const
+{
+    if (imax.negative)
+        return *this;
+    else if (!imin.negative)
+        return IntRange(-imax, -imin);
+    else
+    {
+        SignExtendedNumber imaxAbsNeg = -imax;
+        return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin,
+                        SignExtendedNumber(0));
+    }
+}
+
+IntRange IntRange::unionWith(const IntRange& other) const
+{
+    return IntRange(imin < other.imin ? imin : other.imin,
+                    imax > other.imax ? imax : other.imax);
+}
+
+void IntRange::unionOrAssign(const IntRange& other, bool& union_)
+{
+    if (!union_ || imin > other.imin)
+        imin = other.imin;
+    if (!union_ || imax < other.imax)
+        imax = other.imax;
+    union_ = true;
+}
+
+void IntRange::splitBySign(IntRange& negRange, bool& hasNegRange,
+                           IntRange& nonNegRange, bool& hasNonNegRange) const
+{
+    hasNegRange = imin.negative;
+    if (hasNegRange)
+    {
+        negRange.imin = imin;
+        negRange.imax = imax.negative ? imax : SignExtendedNumber(-1, true);
+    }
+    hasNonNegRange = !imax.negative;
+    if (hasNonNegRange)
+    {
+        nonNegRange.imin = imin.negative ? SignExtendedNumber(0) : imin;
+        nonNegRange.imax = imax;
+    }
+}
+
+
+#if !PERFORM_UNITTEST
+const IntRange& IntRange::dump(const char* funcName, Expression *e) const
+{
+    printf("[(%c)%#018llx, (%c)%#018llx] @ %s ::: %s\n",
+           imin.negative?'-':'+', (unsigned long long)imin.value,
+           imax.negative?'-':'+', (unsigned long long)imax.value,
+           funcName, e->toChars());
+    return *this;
+}
+#endif
+
+//------------------------------------------------------------------------------
+
+#if PERFORM_UNITTEST
+#include <cstdio>
+#include <exception>
+
+class AssertionError : public std::exception {
+public:
+    AssertionError() : std::exception() {}
+};
+
+void _assertPred(uinteger_t x, uinteger_t y, int line) {
+    if (x != y) {
+        printf("Line %d: %#018llx != %#018llx\n", line, x, y);
+        throw AssertionError();
+    }
+}
+void _assertPred(const SignExtendedNumber& x, const SignExtendedNumber& y, int line) {
+    if (x != y) {
+        printf("Line %d: (%c)%#018llx != (%c)%#018llx\n", line,
+            x.negative?'-':'+', x.value,
+            y.negative?'-':'+', y.value);
+        throw AssertionError();
+    }
+}
+void _assertPred(bool x, bool y, int line) {
+    if (x != y) {
+        static const char* const names[] = {"false", "true"};
+        printf("Line %d: %s != %s\n", line, names[x], names[y]);
+        throw AssertionError();
+    }
+}
+#define assertPred(x, y) _assertPred(x, y, __LINE__)
+#define RUN(testName) \
+    try { \
+        testName(); \
+    } catch (const AssertionError&) { \
+        printf("********" #testName " failed\n"); \
+    }
+
+void testAssertSanity() {
+    int saneCount = 0;
+
+    printf("Testing 'assert' sanity. You should see 3 assertion failures below\n");
+
+    assertPred(true, true);
+    try {
+        assertPred(true, false);
+    } catch (const AssertionError&) {
+        ++ saneCount;
+    }
+
+    assertPred(4ULL, 4ULL);
+    try {
+        assertPred(3ULL, -3ULL);
+    } catch (const AssertionError&) {
+        ++ saneCount;
+    }
+
+    assertPred(SignExtendedNumber(5, false), SignExtendedNumber(5, false));
+    try {
+        assertPred(SignExtendedNumber(4, false), SignExtendedNumber(4, true));
+    } catch (const AssertionError&) {
+        ++ saneCount;
+    }
+
+    printf("--------------\n");
+
+    if (saneCount != 3) throw AssertionError();
+}
+
+void testNegation() {
+    SignExtendedNumber s (4);
+    SignExtendedNumber t = -s;
+    assertPred(t.value, -4ULL);
+    assertPred(t.negative, true);
+
+    s = SignExtendedNumber::max();
+    t = -s;
+    assertPred(t.value, 1);
+    assertPred(t.negative, true);
+
+    s = SignExtendedNumber::fromInteger(-4);
+    assertPred(s.value, -4ULL);
+    assertPred(s.negative, true);
+
+    t = -s;
+    assertPred(t.value, 4);
+    assertPred(t.negative, false);
+
+    s = SignExtendedNumber::min();
+    t = -s;
+    assertPred(t.value, UINT64_MAX);
+    assertPred(t.negative, false);
+
+    s = SignExtendedNumber(0);
+    t = -s;
+    assertPred(t.value, 0);
+    assertPred(t.negative, false);
+}
+
+void testCompare() {
+    SignExtendedNumber a = SignExtendedNumber::min();
+    SignExtendedNumber b = SignExtendedNumber(-5, true);
+    SignExtendedNumber c = SignExtendedNumber(0, false);
+    SignExtendedNumber d = SignExtendedNumber(5, false);
+    SignExtendedNumber e = SignExtendedNumber::max();
+
+    assertPred(a == a, true);
+    assertPred(a != a, false);
+    assertPred(a < b, true);
+    assertPred(b < c, true);
+    assertPred(c < d, true);
+    assertPred(d < e, true);
+    assertPred(a < c, true);
+    assertPred(c < e, true);
+    assertPred(b < d, true);
+    assertPred(b < a, false);
+    assertPred(c < b, false);
+    assertPred(d < c, false);
+    assertPred(e < d, false);
+    assertPred(e < c, false);
+    assertPred(d < b, false);
+    assertPred(c < a, false);
+
+    assertPred(a, a);
+    assertPred(SignExtendedNumber::extreme(false), SignExtendedNumber::max());
+    assertPred(SignExtendedNumber::extreme(true), SignExtendedNumber::min());
+}
+
+void testAddition() {
+    assertPred(SignExtendedNumber(4, false) + SignExtendedNumber(8, false),
+               SignExtendedNumber(12, false));
+    assertPred(SignExtendedNumber(4, false) + SignExtendedNumber(-9, true),
+               SignExtendedNumber(-5, true));
+    assertPred(SignExtendedNumber(-9, true) + SignExtendedNumber(4, false),
+               SignExtendedNumber(-5, true));
+    assertPred(SignExtendedNumber(-4, true) + SignExtendedNumber(9, false),
+               SignExtendedNumber(5, false));
+    assertPred(SignExtendedNumber(9, false) + SignExtendedNumber(-4, true),
+               SignExtendedNumber(5, false));
+    assertPred(SignExtendedNumber(9, true) + SignExtendedNumber(-4, false),
+               SignExtendedNumber(5, false));
+    assertPred(SignExtendedNumber(-4, true) + SignExtendedNumber(-6, true),
+               SignExtendedNumber(-10, true));
+    assertPred(SignExtendedNumber::max() + SignExtendedNumber(1, false),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber(UINT64_MAX/2+1, false) + SignExtendedNumber(UINT64_MAX/2+1, false),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber::max() + SignExtendedNumber::min(),
+               SignExtendedNumber(-1, true));
+    assertPred(SignExtendedNumber::min() + SignExtendedNumber(-1, true),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber::max() + SignExtendedNumber::max(),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber::min() + SignExtendedNumber::min(),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber(1, true) + SignExtendedNumber(1, true),
+               SignExtendedNumber::min());
+
+    SignExtendedNumber x(0);
+    assertPred(++x, SignExtendedNumber(1));
+    x = SignExtendedNumber(-1, true);
+    assertPred(++x, SignExtendedNumber(0));
+    x = SignExtendedNumber::min();
+    assertPred(++x, SignExtendedNumber(1, true));
+    x = SignExtendedNumber::max();
+    assertPred(++x, SignExtendedNumber::max());
+}
+
+void testSubtraction() {
+    assertPred(SignExtendedNumber(4, false) - SignExtendedNumber(8, false),
+               SignExtendedNumber(-4, true));
+    assertPred(SignExtendedNumber(4, false) - SignExtendedNumber(-9, true),
+               SignExtendedNumber(13, false));
+    assertPred(SignExtendedNumber(-9, true) - SignExtendedNumber(4, false),
+               SignExtendedNumber(-13, true));
+    assertPred(SignExtendedNumber(-4, true) - SignExtendedNumber(9, false),
+               SignExtendedNumber(-13, true));
+    assertPred(SignExtendedNumber(9, false) - SignExtendedNumber(-4, true),
+               SignExtendedNumber(13, false));
+    assertPred(SignExtendedNumber(9, true) - SignExtendedNumber(-4, false),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber(-4, true) - SignExtendedNumber(-6, true),
+               SignExtendedNumber(2, false));
+    assertPred(SignExtendedNumber::max() - SignExtendedNumber(-1, true),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber::max() - SignExtendedNumber::max(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::max() - SignExtendedNumber::min(),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber::min() - SignExtendedNumber(1, false),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber(1, false) - SignExtendedNumber::min(),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber::min() - SignExtendedNumber::min(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(1, true) - SignExtendedNumber::min(),
+               SignExtendedNumber(1, false));
+}
+
+void testMultiplication() {
+    assertPred(SignExtendedNumber(4, false) * SignExtendedNumber(8, false),
+               SignExtendedNumber(32, false));
+    assertPred(SignExtendedNumber(4, false) * SignExtendedNumber(-9, true),
+               SignExtendedNumber(-36, true));
+    assertPred(SignExtendedNumber(-9, true) * SignExtendedNumber(4, false),
+               SignExtendedNumber(-36, true));
+    assertPred(SignExtendedNumber(-4, true) * SignExtendedNumber(9, false),
+               SignExtendedNumber(-36, true));
+    assertPred(SignExtendedNumber(9, false) * SignExtendedNumber(-4, true),
+               SignExtendedNumber(-36, true));
+    assertPred(SignExtendedNumber(9, true) * SignExtendedNumber(-4, false),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber(-4, true) * SignExtendedNumber(-6, true),
+               SignExtendedNumber(24, false));
+    assertPred(SignExtendedNumber::max() * SignExtendedNumber::max(),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber::max() * SignExtendedNumber(0),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::max() * SignExtendedNumber::min(),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber(0) * SignExtendedNumber::max(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) * SignExtendedNumber(0),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) * SignExtendedNumber::min(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::min() * SignExtendedNumber::max(),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber::min() * SignExtendedNumber(0),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::min() * SignExtendedNumber::min(),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber(-6, false) * SignExtendedNumber(2, false),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber(-6, false) * SignExtendedNumber(-2, true),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber::max() * SignExtendedNumber(-1, true),
+               SignExtendedNumber(1, true));
+    assertPred(SignExtendedNumber::max() * SignExtendedNumber(-2, true),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber::max() * SignExtendedNumber(2, false),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber::min() * SignExtendedNumber(2, false),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber::min() * SignExtendedNumber(-1, true),
+               SignExtendedNumber::max());
+}
+
+void testDivision() {
+    assertPred(SignExtendedNumber(4, false) / SignExtendedNumber(8, false),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(8, false) / SignExtendedNumber(4, false),
+               SignExtendedNumber(2, false));
+    assertPred(SignExtendedNumber(4, false) / SignExtendedNumber(-9, true),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(-9, true) / SignExtendedNumber(4, false),
+               SignExtendedNumber(-2, true));
+    assertPred(SignExtendedNumber(-4, true) / SignExtendedNumber(9, false),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(9, false) / SignExtendedNumber(-4, true),
+               SignExtendedNumber(-2, true));
+    assertPred(SignExtendedNumber(4, true) / SignExtendedNumber(-9, false),
+               SignExtendedNumber(-1, true));
+    assertPred(SignExtendedNumber(-6, true) / SignExtendedNumber(-4, true),
+               SignExtendedNumber(1, false));
+    assertPred(SignExtendedNumber::max() / SignExtendedNumber::max(),
+               SignExtendedNumber(1));
+    assertPred(SignExtendedNumber::max() / SignExtendedNumber(0),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber::max() / SignExtendedNumber::min(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) / SignExtendedNumber::max(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) / SignExtendedNumber(0),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber(0) / SignExtendedNumber::min(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::min() / SignExtendedNumber::max(),
+               SignExtendedNumber(-1, true));
+    assertPred(SignExtendedNumber::min() / SignExtendedNumber(0),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber::min() / SignExtendedNumber::min(),
+               SignExtendedNumber(1));
+    assertPred(SignExtendedNumber(-6, false) / SignExtendedNumber(2, false),
+               SignExtendedNumber((~5ULL)>>1));
+    assertPred(SignExtendedNumber(-6, false) / SignExtendedNumber(-2, true),
+               SignExtendedNumber(3 | 1ULL<<63, true));
+    assertPred(SignExtendedNumber::max() / SignExtendedNumber(-1, true),
+               SignExtendedNumber(1, true));
+    assertPred(SignExtendedNumber::min() / SignExtendedNumber(-1, true),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber::max() / SignExtendedNumber(1, false),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber::min() / SignExtendedNumber(1, false),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber::min() / SignExtendedNumber(2, false),
+               SignExtendedNumber(-(1ULL << 63), true));
+    assertPred(SignExtendedNumber::min() / SignExtendedNumber(-1024, true),
+               SignExtendedNumber(1ULL << 54));
+}
+
+void testModulus() {
+    assertPred(SignExtendedNumber(4, false) % SignExtendedNumber(8, false),
+               SignExtendedNumber(4, false));
+    assertPred(SignExtendedNumber(8, false) % SignExtendedNumber(4, false),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(4, false) % SignExtendedNumber(-9, true),
+               SignExtendedNumber(4, false));
+    assertPred(SignExtendedNumber(-9, true) % SignExtendedNumber(4, false),
+               SignExtendedNumber(-1, true));
+    assertPred(SignExtendedNumber(-4, true) % SignExtendedNumber(9, false),
+               SignExtendedNumber(-4, true));
+    assertPred(SignExtendedNumber(9, false) % SignExtendedNumber(-4, true),
+               SignExtendedNumber(1, false));
+    assertPred(SignExtendedNumber(4, true) % SignExtendedNumber(-9, false),
+               SignExtendedNumber(-5, true));
+    assertPred(SignExtendedNumber(-6, true) % SignExtendedNumber(-4, true),
+               SignExtendedNumber(-2, true));
+    assertPred(SignExtendedNumber::max() % SignExtendedNumber::max(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::max() % SignExtendedNumber(0),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::max() % SignExtendedNumber::min(),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber(0) % SignExtendedNumber::max(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) % SignExtendedNumber(0),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) % SignExtendedNumber::min(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::min() % SignExtendedNumber::max(),
+               SignExtendedNumber(-1, true));
+    assertPred(SignExtendedNumber::min() % SignExtendedNumber(0),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::min() % SignExtendedNumber::min(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(-6, false) % SignExtendedNumber(2, false),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(-6, false) % SignExtendedNumber(-2, true),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::max() % SignExtendedNumber(-1, true),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::min() % SignExtendedNumber(-1, true),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::max() % SignExtendedNumber(1, false),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::min() % SignExtendedNumber(1, false),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::min() % SignExtendedNumber(2, false),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber::min() % SignExtendedNumber(999, false),
+               SignExtendedNumber(-160, true));
+}
+
+void testShift() {
+    assertPred(SignExtendedNumber(0) << SignExtendedNumber(4),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) << SignExtendedNumber(74),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) << SignExtendedNumber(-5, true),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) << SignExtendedNumber::max(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) << SignExtendedNumber::min(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(1) << SignExtendedNumber(4),
+               SignExtendedNumber(16));
+    assertPred(SignExtendedNumber(1) << SignExtendedNumber(74),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber(1) << SignExtendedNumber(-5, true),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber(1) << SignExtendedNumber::max(),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber(1) << SignExtendedNumber::min(),
+               SignExtendedNumber::max());
+    assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber(4),
+               SignExtendedNumber(-16, true));
+    assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber(74),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber(-5, true),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber::max(),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber::min(),
+               SignExtendedNumber::min());
+    assertPred(SignExtendedNumber(0xabcdef) << SignExtendedNumber(12, false),
+               SignExtendedNumber(0xabcdef000ULL));
+    assertPred(SignExtendedNumber(0xabcdef) << SignExtendedNumber(40, false),
+               SignExtendedNumber(0xabcdef0000000000ULL));
+    assertPred(SignExtendedNumber(0xabcdef) << SignExtendedNumber(41, false),
+               SignExtendedNumber::max());
+
+
+    assertPred(SignExtendedNumber(0) >> SignExtendedNumber(4),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) >> SignExtendedNumber(74),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) >> SignExtendedNumber(-5, true),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) >> SignExtendedNumber::max(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(0) >> SignExtendedNumber::min(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(16) >> SignExtendedNumber(4),
+               SignExtendedNumber(1));
+    assertPred(SignExtendedNumber(16) >> SignExtendedNumber(74),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(16) >> SignExtendedNumber(-5, true),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(16) >> SignExtendedNumber::max(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(16) >> SignExtendedNumber::min(),
+               SignExtendedNumber(0));
+    assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber(4),
+               SignExtendedNumber(-2, true));
+    assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber(74),
+               SignExtendedNumber(-1, true));
+    assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber(-5, true),
+               SignExtendedNumber(-1, true));
+    assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber::max(),
+               SignExtendedNumber(-1, true));
+    assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber::min(),
+               SignExtendedNumber(-1, true));
+    assertPred(SignExtendedNumber(0xabcdef, false) >> SignExtendedNumber(12, false),
+               SignExtendedNumber(0xabcULL));
+    assertPred(SignExtendedNumber(0xabcdef, true) >> SignExtendedNumber(12, false),
+               SignExtendedNumber(0xFFF0000000000ABCULL, true));
+    assertPred(SignExtendedNumber::min() >> SignExtendedNumber(1, false),
+               SignExtendedNumber(0x8000000000000000ULL, true));
+    assertPred(SignExtendedNumber::min() >> SignExtendedNumber(63, false),
+               SignExtendedNumber(-2, true));
+    assertPred(SignExtendedNumber::min() >> SignExtendedNumber(65, false),
+               SignExtendedNumber(-1, true));
+}
+
+void testFromNumbers() {
+    SignExtendedNumber a[] = {
+        SignExtendedNumber(12, false),
+        SignExtendedNumber(-35, true),
+        SignExtendedNumber(40, false),
+        SignExtendedNumber(-21, true),
+        SignExtendedNumber::min()
+    };
+
+    IntRange ir1 = IntRange::fromNumbers2(a);
+    assertPred(ir1.imin, SignExtendedNumber(-35, true));
+    assertPred(ir1.imax, SignExtendedNumber(12, false));
+
+    IntRange ir2 = IntRange::fromNumbers2(a+1);
+    assertPred(ir2.imin, SignExtendedNumber(-35, true));
+    assertPred(ir2.imax, SignExtendedNumber(40, false));
+
+    IntRange ir3 = IntRange::fromNumbers4(a);
+    assertPred(ir3.imin, SignExtendedNumber(-35, true));
+    assertPred(ir3.imax, SignExtendedNumber(40, false));
+
+    IntRange ir4 = IntRange::fromNumbers4(a+1);
+    assertPred(ir4.imin, SignExtendedNumber::min());
+    assertPred(ir4.imax, SignExtendedNumber(40, false));
+
+    assertPred(ir4.contains(ir3), true);
+    assertPred(ir1.contains(ir2), false);
+
+    IntRange ir5 = IntRange::widest();
+    assertPred(ir5.imin, SignExtendedNumber::min());
+    assertPred(ir5.imax, SignExtendedNumber::max());
+    assertPred(ir5.contains(ir4), true);
+}
+
+void testContainsZero() {
+    IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(4));
+    assertPred(ir1.containsZero(), true);
+
+    IntRange ir2 (SignExtendedNumber(-4, true), SignExtendedNumber(0));
+    assertPred(ir2.containsZero(), true);
+
+    IntRange ir3 (SignExtendedNumber(-5, true), SignExtendedNumber(5));
+    assertPred(ir3.containsZero(), true);
+
+    assertPred(IntRange::widest().containsZero(), true);
+
+    IntRange ir4 (SignExtendedNumber(8), SignExtendedNumber(9));
+    assertPred(ir4.containsZero(), false);
+
+    IntRange ir5 (SignExtendedNumber(-5, true), SignExtendedNumber(-2, true));
+    assertPred(ir5.containsZero(), false);
+
+    IntRange ir6 (SignExtendedNumber(0), SignExtendedNumber(0));
+    assertPred(ir6.containsZero(), true);
+}
+
+void testCast() {
+    {
+        IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(0xFFFF));
+        ir1.castUnsigned(0xFF);
+        assertPred(ir1.imin, SignExtendedNumber(0));
+        assertPred(ir1.imax, SignExtendedNumber(0xFF));
+
+        IntRange ir2 (SignExtendedNumber(0x101), SignExtendedNumber(0x105));
+        ir2.castUnsigned(0xFF);
+        assertPred(ir2.imin, SignExtendedNumber(1));
+        assertPred(ir2.imax, SignExtendedNumber(5));
+
+        IntRange ir3 (SignExtendedNumber(-7, true), SignExtendedNumber(7, false));
+        ir3.castUnsigned(0xFF);
+        assertPred(ir3.imin, SignExtendedNumber(0));
+        assertPred(ir3.imax, SignExtendedNumber(0xFF));
+
+        IntRange ir4 (SignExtendedNumber(0x997F), SignExtendedNumber(0x9999));
+        ir4.castUnsigned(0xFF);
+        assertPred(ir4.imin, SignExtendedNumber(0x7F));
+        assertPred(ir4.imax, SignExtendedNumber(0x99));
+
+        IntRange ir5 (SignExtendedNumber(-1, true), SignExtendedNumber(1, false));
+        ir5.castUnsigned(UINT64_MAX);
+        assertPred(ir5.imin, SignExtendedNumber(0));
+        assertPred(ir5.imax, SignExtendedNumber::max());
+
+        IntRange ir6 (SignExtendedNumber::min(), SignExtendedNumber(0));
+        ir6.castUnsigned(UINT64_MAX);
+        assertPred(ir6.imin, SignExtendedNumber(0));
+        assertPred(ir6.imax, SignExtendedNumber::max());
+
+        IntRange ir7 (SignExtendedNumber::min(), SignExtendedNumber(-0x80, true));
+        ir7.castUnsigned(UINT64_MAX);
+        assertPred(ir7.imin, SignExtendedNumber(0));
+        assertPred(ir7.imax, SignExtendedNumber(-0x80, false));
+
+        IntRange ir8 = IntRange::widest();
+        ir8.castUnsigned(0xFF);
+        assertPred(ir8.imin, SignExtendedNumber(0));
+        assertPred(ir8.imax, SignExtendedNumber(0xFF));
+    }
+
+    {
+        IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(0xFFFF));
+        ir1.castSigned(0xFF);
+        assertPred(ir1.imin, SignExtendedNumber(-0x80, true));
+        assertPred(ir1.imax, SignExtendedNumber(0x7F, false));
+
+        IntRange ir2 (SignExtendedNumber(0x101), SignExtendedNumber(0x105));
+        ir2.castSigned(0xFF);
+        assertPred(ir2.imin, SignExtendedNumber(1));
+        assertPred(ir2.imax, SignExtendedNumber(5));
+
+        IntRange ir3 (SignExtendedNumber(-7, true), SignExtendedNumber(7, false));
+        ir3.castSigned(0xFF);
+        assertPred(ir3.imin, SignExtendedNumber(-7, true));
+        assertPred(ir3.imax, SignExtendedNumber(7, false));
+
+        IntRange ir4 (SignExtendedNumber(0x997F), SignExtendedNumber(0x9999));
+        ir4.castSigned(0xFF);
+        assertPred(ir4.imin, SignExtendedNumber(-0x80, true));
+        assertPred(ir4.imax, SignExtendedNumber(0x7F, false));
+
+        IntRange ir5 (SignExtendedNumber(-0xFF, true), SignExtendedNumber(-0x80, true));
+        ir5.castSigned(0xFF);
+        assertPred(ir5.imin, SignExtendedNumber(-0x80, true));
+        assertPred(ir5.imax, SignExtendedNumber(0x7F, false));
+
+        IntRange ir6 (SignExtendedNumber(-0x80, true), SignExtendedNumber(-0x80, true));
+        ir6.castSigned(0xFF);
+        assertPred(ir6.imin, SignExtendedNumber(-0x80, true));
+        assertPred(ir6.imax, SignExtendedNumber(-0x80, true));
+
+        IntRange ir7 = IntRange::widest();
+        ir7.castSigned(0xFFFFFFFFULL);
+        assertPred(ir7.imin, SignExtendedNumber(-0x80000000ULL, true));
+        assertPred(ir7.imax, SignExtendedNumber( 0x7FFFFFFFULL, false));
+    }
+
+    {
+        IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(0x9999));
+        ir1.castDchar();
+        assertPred(ir1.imin, SignExtendedNumber(0));
+        assertPred(ir1.imax, SignExtendedNumber(0x9999));
+
+        IntRange ir2 (SignExtendedNumber(0xFFFF), SignExtendedNumber(0x7FFFFFFF));
+        ir2.castDchar();
+        assertPred(ir2.imin, SignExtendedNumber(0xFFFF));
+        assertPred(ir2.imax, SignExtendedNumber(0x10FFFF));
+
+        IntRange ir3 = IntRange::widest();
+        ir3.castDchar();
+        assertPred(ir3.imin, SignExtendedNumber(0));
+        assertPred(ir3.imax, SignExtendedNumber(0x10FFFF));
+    }
+}
+
+void testAbsNeg() {
+    IntRange ir1 = IntRange(SignExtendedNumber(5), SignExtendedNumber(104)).absNeg();
+    assertPred(ir1.imin, SignExtendedNumber(-104, true));
+    assertPred(ir1.imax, SignExtendedNumber(-5, true));
+
+    IntRange ir2 = IntRange(SignExtendedNumber(-46, true), SignExtendedNumber(-3, true)).absNeg();
+    assertPred(ir2.imin, SignExtendedNumber(-46, true));
+    assertPred(ir2.imax, SignExtendedNumber(-3, true));
+
+    IntRange ir3 = IntRange(SignExtendedNumber(-7, true), SignExtendedNumber(9)).absNeg();
+    assertPred(ir3.imin, SignExtendedNumber(-9, true));
+    assertPred(ir3.imax, SignExtendedNumber(0));
+
+    IntRange ir4 = IntRange(SignExtendedNumber(-12, true), SignExtendedNumber(2)).absNeg();
+    assertPred(ir4.imin, SignExtendedNumber(-12, true));
+    assertPred(ir4.imax, SignExtendedNumber(0));
+
+    IntRange ir5 = IntRange::widest().absNeg();
+    assertPred(ir5.imin, SignExtendedNumber::min());
+    assertPred(ir5.imax, SignExtendedNumber(0));
+
+    IntRange ir6 = IntRange(SignExtendedNumber(0), SignExtendedNumber::max()).absNeg();
+    assertPred(ir6.imin, SignExtendedNumber(1, true));
+    assertPred(ir6.imax, SignExtendedNumber(0));
+}
+
+int main() {
+    RUN(testAssertSanity);
+    RUN(testNegation);
+    RUN(testCompare);
+    RUN(testAddition);
+    RUN(testSubtraction);
+    RUN(testMultiplication);
+    RUN(testDivision);
+    RUN(testModulus);
+    RUN(testShift);
+    RUN(testFromNumbers);
+    RUN(testContainsZero);
+    RUN(testCast);
+    RUN(testAbsNeg);
+    printf("Finished all tests.\n");
+}
+
+
+#endif
+
+
diff --git a/gcc/d/dfrontend/intrange.h b/gcc/d/dfrontend/intrange.h
new file mode 100644
index 00000000000..446701cf767
--- /dev/null
+++ b/gcc/d/dfrontend/intrange.h
@@ -0,0 +1,153 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by KennyTM
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/intrange.h
+ */
+
+#ifndef DMD_SXNUM_H
+#define DMD_SXNUM_H
+
+#include "mars.h"   // for uinteger_t
+class Type;
+class Expression;
+
+/**
+This class represents a "sign-extended number", i.e. a 65-bit number, which can
+represent all built-in integer types in D. This class is mainly used for
+performing value-range propagation only, therefore all arithmetic are done with
+saturation, not wrapping as usual.
+*/
+struct SignExtendedNumber
+{
+    /// The lower 64-bit of the number.
+    uinteger_t value;
+    /// The sign (i.e. the most significant bit) of the number.
+    bool negative;
+
+    /// Create an uninitialized sign-extended number.
+    SignExtendedNumber() {}
+
+    /// Create a sign-extended number from an unsigned 64-bit number.
+    SignExtendedNumber(uinteger_t value_)
+        : value(value_), negative(false) {}
+    /// Create a sign-extended number from the lower 64-bit and the sign bit.
+    SignExtendedNumber(uinteger_t value_, bool negative_)
+        : value(value_), negative(negative_) {}
+
+    /// Create a sign-extended number from a signed 64-bit number.
+    static SignExtendedNumber fromInteger(uinteger_t value_);
+
+    /// Get the minimum or maximum value of a sign-extended number.
+    static SignExtendedNumber extreme(bool minimum);
+
+    // These names probably shouldn't be used anyway, as they are common macros
+#undef max
+#undef min
+    static SignExtendedNumber max();
+    static SignExtendedNumber min() { return SignExtendedNumber(0, true); }
+
+    /// Check if the sign-extended number is minimum or zero.
+    bool isMinimum() const { return negative && value == 0; }
+
+    /// Compare two sign-extended number.
+    bool operator==(const SignExtendedNumber&) const;
+    bool operator!=(const SignExtendedNumber& a) const { return !(*this == a); }
+    bool operator<(const SignExtendedNumber&) const;
+    bool operator>(const SignExtendedNumber& a) const { return a < *this; }
+    bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); }
+    bool operator>=(const SignExtendedNumber& a) const { return !(*this < a); }
+
+    /// Compute the saturated negation of a sign-extended number.
+    SignExtendedNumber operator-() const;
+
+    /// Compute the saturated sum of two sign-extended number.
+    SignExtendedNumber operator+(const SignExtendedNumber&) const;
+    /// Compute the saturated difference of two sign-extended number.
+    SignExtendedNumber operator-(const SignExtendedNumber& a) const;
+    /// Compute the saturated product of two sign-extended number.
+    SignExtendedNumber operator*(const SignExtendedNumber&) const;
+    /// Compute the saturated quotient of two sign-extended number.
+    SignExtendedNumber operator/(const SignExtendedNumber&) const;
+    /// Compute the saturated modulus of two sign-extended number.
+    SignExtendedNumber operator%(const SignExtendedNumber&) const;
+
+    /// Increase the sign-extended number by 1 (saturated).
+    SignExtendedNumber& operator++();
+
+    /// Compute the saturated shifts of two sign-extended number.
+    SignExtendedNumber operator<<(const SignExtendedNumber&) const;
+    SignExtendedNumber operator>>(const SignExtendedNumber&) const;
+};
+
+/**
+This class represents a range of integers, denoted by its lower and upper bounds
+(inclusive).
+*/
+struct IntRange
+{
+    SignExtendedNumber imin, imax;
+
+    /// Create an uninitialized range.
+    IntRange() {}
+
+    /// Create a range consisting of a single number.
+    IntRange(const SignExtendedNumber& a)
+        : imin(a), imax(a) {}
+    /// Create a range with the lower and upper bounds.
+    IntRange(const SignExtendedNumber& lower, const SignExtendedNumber& upper)
+        : imin(lower), imax(upper) {}
+
+    /// Create the tightest range containing all valid integers in the specified
+    /// type.
+    static IntRange fromType(Type *type);
+    /// Create the tightest range containing all valid integers in the type with
+    /// a forced signedness.
+    static IntRange fromType(Type *type, bool isUnsigned);
+
+
+    /// Create the tightest range containing all specified numbers.
+    static IntRange fromNumbers2(const SignExtendedNumber numbers[2]);
+    static IntRange fromNumbers4(const SignExtendedNumber numbers[4]);
+
+    /// Create the widest range possible.
+    static IntRange widest();
+
+    /// Cast the integer range to a signed type with the given size mask.
+    IntRange& castSigned(uinteger_t mask);
+    /// Cast the integer range to an unsigned type with the given size mask.
+    IntRange& castUnsigned(uinteger_t mask);
+    /// Cast the integer range to the dchar type.
+    IntRange& castDchar();
+
+    /// Cast the integer range to a specific type.
+    IntRange& cast(Type *type);
+    /// Cast the integer range to a specific type, forcing it to be unsigned.
+    IntRange& castUnsigned(Type *type);
+
+    /// Check if this range contains another range.
+    bool contains(const IntRange& a) const;
+
+    /// Check if this range contains 0.
+    bool containsZero() const;
+
+    /// Compute the range of the negated absolute values of the original range.
+    IntRange absNeg() const;
+
+    /// Compute the union of two ranges.
+    IntRange unionWith(const IntRange& other) const;
+    void unionOrAssign(const IntRange& other, bool& union_);
+
+    /// Dump the content of the integer range to the console.
+    const IntRange& dump(const char* funcName, Expression *e) const;
+
+    /// Split the range into two nonnegative- and negative-only subintervals.
+    void splitBySign(IntRange& negRange, bool& hasNegRange,
+                     IntRange& nonNegRange, bool& hasNonNegRange) const;
+};
+
+#endif
diff --git a/gcc/d/dfrontend/json.c b/gcc/d/dfrontend/json.c
new file mode 100644
index 00000000000..6673d415eed
--- /dev/null
+++ b/gcc/d/dfrontend/json.c
@@ -0,0 +1,890 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/json.c
+ */
+
+// This implements the JSON capability.
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "rmem.h"
+
+#include "dsymbol.h"
+#include "template.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "enum.h"
+#include "module.h"
+#include "json.h"
+#include "mtype.h"
+#include "attrib.h"
+#include "cond.h"
+#include "init.h"
+#include "import.h"
+#include "id.h"
+#include "hdrgen.h"
+
+class ToJsonVisitor : public Visitor
+{
+public:
+    OutBuffer *buf;
+    int indentLevel;
+    const char *filename;
+
+    ToJsonVisitor(OutBuffer *buf)
+        : buf(buf), indentLevel(0), filename(NULL)
+    {
+    }
+
+    void indent()
+    {
+        if (buf->offset >= 1 &&
+            buf->data[buf->offset - 1] == '\n')
+            for (int i = 0; i < indentLevel; i++)
+                buf->writeByte(' ');
+    }
+
+    void removeComma()
+    {
+        if (buf->offset >= 2 &&
+            buf->data[buf->offset - 2] == ',' &&
+            (buf->data[buf->offset - 1] == '\n' || buf->data[buf->offset - 1] == ' '))
+            buf->offset -= 2;
+    }
+
+    void comma()
+    {
+        if (indentLevel > 0)
+            buf->writestring(",\n");
+    }
+
+    void stringStart()
+    {
+        buf->writeByte('\"');
+    }
+
+    void stringEnd()
+    {
+        buf->writeByte('\"');
+    }
+
+    void stringPart(const char *s)
+    {
+        for (; *s; s++)
+        {
+            utf8_t c = (utf8_t) *s;
+            switch (c)
+            {
+                case '\n':
+                    buf->writestring("\\n");
+                    break;
+
+                case '\r':
+                    buf->writestring("\\r");
+                    break;
+
+                case '\t':
+                    buf->writestring("\\t");
+                    break;
+
+                case '\"':
+                    buf->writestring("\\\"");
+                    break;
+
+                case '\\':
+                    buf->writestring("\\\\");
+                    break;
+
+                case '\b':
+                    buf->writestring("\\b");
+                    break;
+
+                case '\f':
+                    buf->writestring("\\f");
+                    break;
+
+                default:
+                    if (c < 0x20)
+                        buf->printf("\\u%04x", c);
+                    else
+                    {
+                        // Note that UTF-8 chars pass through here just fine
+                        buf->writeByte(c);
+                    }
+                    break;
+            }
+        }
+    }
+
+    // Json value functions
+
+    /*********************************
+     * Encode string into buf, and wrap it in double quotes.
+     */
+    void value(const char *s)
+    {
+        stringStart();
+        stringPart(s);
+        stringEnd();
+    }
+
+    void value(int value)
+    {
+        buf->printf("%d", value);
+    }
+
+    void valueBool(bool value)
+    {
+        buf->writestring(value ? "true" : "false");
+    }
+
+    /*********************************
+     * Item is an intented value and a comma, for use in arrays
+     */
+    void item(const char *s)
+    {
+        indent();
+        value(s);
+        comma();
+    }
+
+    void item(int i)
+    {
+        indent();
+        value(i);
+        comma();
+    }
+
+    void itemBool(bool b)
+    {
+        indent();
+        valueBool(b);
+        comma();
+    }
+
+
+    // Json array functions
+
+    void arrayStart()
+    {
+        indent();
+        buf->writestring("[\n");
+        indentLevel++;
+    }
+
+    void arrayEnd()
+    {
+        indentLevel--;
+        removeComma();
+        if (buf->offset >= 2 &&
+            buf->data[buf->offset - 2] == '[' &&
+            buf->data[buf->offset - 1] == '\n')
+            buf->offset -= 1;
+        else if (!(buf->offset >= 1 &&
+            buf->data[buf->offset - 1] == '['))
+        {
+            buf->writestring("\n");
+            indent();
+        }
+        buf->writestring("]");
+        comma();
+    }
+
+
+    // Json object functions
+
+    void objectStart()
+    {
+        indent();
+        buf->writestring("{\n");
+        indentLevel++;
+    }
+
+    void objectEnd()
+    {
+        indentLevel--;
+        removeComma();
+        if (buf->offset >= 2 &&
+            buf->data[buf->offset - 2] == '{' &&
+            buf->data[buf->offset - 1] == '\n')
+            buf->offset -= 1;
+        else
+        {
+            buf->writestring("\n");
+            indent();
+        }
+        buf->writestring("}");
+        comma();
+    }
+
+    // Json object property functions
+
+    void propertyStart(const char *name)
+    {
+        indent();
+        value(name);
+        buf->writestring(" : ");
+    }
+
+    void property(const char *name, const char *s)
+    {
+        if (s == NULL) return;
+
+        propertyStart(name);
+        value(s);
+        comma();
+    }
+
+    void property(const char *name, int i)
+    {
+        propertyStart(name);
+        value(i);
+        comma();
+    }
+
+    void propertyBool(const char *name, bool b)
+    {
+        propertyStart(name);
+        valueBool(b);
+        comma();
+    }
+
+
+    void property(const char *name, TRUST trust)
+    {
+        switch (trust)
+        {
+            case TRUSTdefault:
+                // Should not be printed
+                //property(name, "default");
+                break;
+            case TRUSTsystem:
+                property(name, "system");
+                break;
+            case TRUSTtrusted:
+                property(name, "trusted");
+                break;
+            case TRUSTsafe:
+                property(name, "safe");
+                break;
+            default:
+                assert(false);
+        }
+    }
+
+    void property(const char *name, PURE purity)
+    {
+        switch (purity)
+        {
+            case PUREimpure:
+                // Should not be printed
+                //property(name, "impure");
+                break;
+            case PUREweak:
+                property(name, "weak");
+                break;
+            case PUREconst:
+                property(name, "const");
+                break;
+            case PUREstrong:
+                property(name, "strong");
+                break;
+            case PUREfwdref:
+                property(name, "fwdref");
+                break;
+            default:
+                assert(false);
+        }
+    }
+
+    void property(const char *name, LINK linkage)
+    {
+        switch (linkage)
+        {
+            case LINKdefault:
+                // Should not be printed
+                //property(name, "default");
+                break;
+            case LINKd:
+                // Should not be printed
+                //property(name, "d");
+                break;
+            case LINKc:
+                property(name, "c");
+                break;
+            case LINKcpp:
+                property(name, "cpp");
+                break;
+            case LINKwindows:
+                property(name, "windows");
+                break;
+            case LINKpascal:
+                property(name, "pascal");
+                break;
+            default:
+                assert(false);
+        }
+    }
+
+    void propertyStorageClass(const char *name, StorageClass stc)
+    {
+        stc &= STCStorageClass;
+        if (stc)
+        {
+            propertyStart(name);
+            arrayStart();
+
+            while (stc)
+            {
+                const char *p = stcToChars(stc);
+                assert(p);
+                item(p);
+            }
+
+            arrayEnd();
+        }
+    }
+
+    void property(const char *linename, const char *charname, Loc *loc)
+    {
+        if (loc)
+        {
+            const char *filename = loc->filename;
+            if (filename)
+            {
+                if (!this->filename || strcmp(filename, this->filename))
+                {
+                    this->filename = filename;
+                    property("file", filename);
+                }
+            }
+
+            if (loc->linnum)
+            {
+                property(linename, loc->linnum);
+                if (loc->charnum)
+                    property(charname, loc->charnum);
+            }
+        }
+    }
+
+    void property(const char *name, Type *type)
+    {
+        if (type)
+        {
+            property(name, type->toChars());
+        }
+    }
+
+    void property(const char *name, const char *deconame, Type *type)
+    {
+        if (type)
+        {
+            if (type->deco)
+                property(deconame, type->deco);
+            else
+                property(name, type->toChars());
+        }
+    }
+
+    void property(const char *name, Parameters *parameters)
+    {
+        if (parameters == NULL || parameters->dim == 0)
+            return;
+
+        propertyStart(name);
+        arrayStart();
+
+        if (parameters)
+        {
+            for (size_t i = 0; i < parameters->dim; i++)
+            {
+                Parameter *p = (*parameters)[i];
+                objectStart();
+
+                if (p->ident)
+                    property("name", p->ident->toChars());
+
+                property("type", "deco", p->type);
+
+                propertyStorageClass("storageClass", p->storageClass);
+
+                if (p->defaultArg)
+                    property("default", p->defaultArg->toChars());
+
+
+                objectEnd();
+            }
+        }
+
+        arrayEnd();
+    }
+
+    /* ========================================================================== */
+
+    void jsonProperties(Dsymbol *s)
+    {
+        if (s->isModule())
+            return;
+
+        if (!s->isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes
+        {
+            property("name", s->toChars());
+            property("kind", s->kind());
+        }
+
+        if (s->prot().kind != PROTpublic)   // TODO: How about package(names)?
+            property("protection", protectionToChars(s->prot().kind));
+
+        if (EnumMember *em = s->isEnumMember())
+        {
+            if (em->origValue)
+                property("value", em->origValue->toChars());
+        }
+
+        property("comment", (const char *)s->comment);
+
+        property("line", "char", &s->loc);
+    }
+
+    void jsonProperties(Declaration *d)
+    {
+        jsonProperties((Dsymbol *)d);
+
+        propertyStorageClass("storageClass", d->storage_class);
+
+        property("type", "deco", d->type);
+
+        // Emit originalType if it differs from type
+        if (d->type != d->originalType && d->originalType)
+        {
+            const char *ostr = d->originalType->toChars();
+            if (d->type)
+            {
+                const char *tstr = d->type->toChars();
+                if (strcmp(tstr, ostr))
+                {
+                    //printf("tstr = %s, ostr = %s\n", tstr, ostr);
+                    property("originalType", ostr);
+                }
+            }
+            else
+                property("originalType", ostr);
+        }
+    }
+
+    void jsonProperties(TemplateDeclaration *td)
+    {
+        jsonProperties((Dsymbol *)td);
+
+        if (td->onemember && td->onemember->isCtorDeclaration())
+            property("name", "this");  // __ctor -> this
+        else
+            property("name", td->ident->toChars());  // Foo(T) -> Foo
+    }
+
+    /* ========================================================================== */
+
+    void visit(Dsymbol *s)
+    {
+    }
+
+    void visit(Module *s)
+    {
+        objectStart();
+
+        if (s->md)
+            property("name", s->md->toChars());
+
+        property("kind", s->kind());
+
+        filename = s->srcfile->toChars();
+        property("file", filename);
+
+        property("comment", (const char *)s->comment);
+
+        propertyStart("members");
+        arrayStart();
+        for (size_t i = 0; i < s->members->dim; i++)
+        {
+            (*s->members)[i]->accept(this);
+        }
+        arrayEnd();
+
+        objectEnd();
+    }
+
+    void visit(Import *s)
+    {
+        if (s->id == Id::object)
+            return;
+
+        objectStart();
+
+        propertyStart("name");
+        stringStart();
+        if (s->packages && s->packages->dim)
+        {
+            for (size_t i = 0; i < s->packages->dim; i++)
+            {
+                Identifier *pid = (*s->packages)[i];
+                stringPart(pid->toChars());
+                buf->writeByte('.');
+            }
+        }
+        stringPart(s->id->toChars());
+        stringEnd();
+        comma();
+
+        property("kind", s->kind());
+        property("comment", (const char *)s->comment);
+        property("line", "char", &s->loc);
+        if (s->prot().kind != PROTpublic)
+            property("protection", protectionToChars(s->prot().kind));
+        if (s->aliasId)
+            property("alias", s->aliasId->toChars());
+
+        bool hasRenamed = false;
+        bool hasSelective = false;
+        for (size_t i = 0; i < s->aliases.dim; i++)
+        {
+            // avoid empty "renamed" and "selective" sections
+            if (hasRenamed && hasSelective)
+                break;
+            else if (s->aliases[i])
+                hasRenamed = true;
+            else
+                hasSelective = true;
+        }
+
+        if (hasRenamed)
+        {
+            // import foo : alias1 = target1;
+            propertyStart("renamed");
+            objectStart();
+            for (size_t i = 0; i < s->aliases.dim; i++)
+            {
+                Identifier *name = s->names[i];
+                Identifier *alias = s->aliases[i];
+                if (alias) property(alias->toChars(), name->toChars());
+            }
+            objectEnd();
+        }
+
+        if (hasSelective)
+        {
+            // import foo : target1;
+            propertyStart("selective");
+            arrayStart();
+            for (size_t i = 0; i < s->names.dim; i++)
+            {
+                Identifier *name = s->names[i];
+                if (!s->aliases[i]) item(name->toChars());
+            }
+            arrayEnd();
+        }
+
+        objectEnd();
+    }
+
+    void visit(AttribDeclaration *d)
+    {
+        Dsymbols *ds = d->include(NULL, NULL);
+
+        if (ds)
+        {
+            for (size_t i = 0; i < ds->dim; i++)
+            {
+                Dsymbol *s = (*ds)[i];
+                s->accept(this);
+            }
+        }
+    }
+
+    void visit(ConditionalDeclaration *d)
+    {
+        if (d->condition->inc)
+        {
+            visit((AttribDeclaration *)d);
+        }
+    }
+
+    void visit(TypeInfoDeclaration *d) {}
+    void visit(PostBlitDeclaration *d) {}
+
+    void visit(Declaration *d)
+    {
+        objectStart();
+
+        //property("unknown", "declaration");
+
+        jsonProperties(d);
+
+        objectEnd();
+    }
+
+    void visit(AggregateDeclaration *d)
+    {
+        objectStart();
+
+        jsonProperties(d);
+
+        ClassDeclaration *cd = d->isClassDeclaration();
+        if (cd)
+        {
+            if (cd->baseClass && cd->baseClass->ident != Id::Object)
+            {
+                property("base", cd->baseClass->toPrettyChars(true));
+            }
+            if (cd->interfaces.length)
+            {
+                propertyStart("interfaces");
+                arrayStart();
+                for (size_t i = 0; i < cd->interfaces.length; i++)
+                {
+                    BaseClass *b = cd->interfaces.ptr[i];
+                    item(b->sym->toPrettyChars(true));
+                }
+                arrayEnd();
+            }
+        }
+
+        if (d->members)
+        {
+            propertyStart("members");
+            arrayStart();
+            for (size_t i = 0; i < d->members->dim; i++)
+            {
+                Dsymbol *s = (*d->members)[i];
+                s->accept(this);
+            }
+            arrayEnd();
+        }
+
+        objectEnd();
+    }
+
+    void visit(FuncDeclaration *d)
+    {
+        objectStart();
+
+        jsonProperties(d);
+
+        TypeFunction *tf = (TypeFunction *)d->type;
+        if (tf && tf->ty == Tfunction)
+            property("parameters", tf->parameters);
+
+        property("endline", "endchar", &d->endloc);
+
+        if (d->foverrides.dim)
+        {
+            propertyStart("overrides");
+            arrayStart();
+            for (size_t i = 0; i < d->foverrides.dim; i++)
+            {
+                FuncDeclaration *fd = d->foverrides[i];
+                item(fd->toPrettyChars());
+            }
+            arrayEnd();
+        }
+
+        if (d->fdrequire)
+        {
+            propertyStart("in");
+            d->fdrequire->accept(this);
+        }
+
+        if (d->fdensure)
+        {
+            propertyStart("out");
+            d->fdensure->accept(this);
+        }
+
+        objectEnd();
+    }
+
+    void visit(TemplateDeclaration *d)
+    {
+        objectStart();
+
+        // TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one
+        property("kind", "template");
+
+        jsonProperties(d);
+
+        propertyStart("parameters");
+        arrayStart();
+        for (size_t i = 0; i < d->parameters->dim; i++)
+        {
+            TemplateParameter *s = (*d->parameters)[i];
+            objectStart();
+
+            property("name", s->ident->toChars());
+
+            TemplateTypeParameter *type = s->isTemplateTypeParameter();
+            if (type)
+            {
+                if (s->isTemplateThisParameter())
+                    property("kind", "this");
+                else
+                    property("kind", "type");
+                property("type", "deco", type->specType);
+
+                property("default", "defaultDeco", type->defaultType);
+            }
+
+            TemplateValueParameter *value = s->isTemplateValueParameter();
+            if (value)
+            {
+                property("kind", "value");
+
+                property("type", "deco", value->valType);
+
+                if (value->specValue)
+                    property("specValue", value->specValue->toChars());
+
+                if (value->defaultValue)
+                    property("defaultValue", value->defaultValue->toChars());
+            }
+
+            TemplateAliasParameter *alias = s->isTemplateAliasParameter();
+            if (alias)
+            {
+                property("kind", "alias");
+
+                property("type", "deco", alias->specType);
+
+                if (alias->specAlias)
+                    property("specAlias", alias->specAlias->toChars());
+
+                if (alias->defaultAlias)
+                    property("defaultAlias", alias->defaultAlias->toChars());
+            }
+
+            TemplateTupleParameter *tuple = s->isTemplateTupleParameter();
+            if (tuple)
+            {
+                property("kind", "tuple");
+            }
+
+            objectEnd();
+        }
+        arrayEnd();
+
+        Expression *expression = d->constraint;
+        if (expression)
+        {
+            property("constraint", expression->toChars());
+        }
+
+        propertyStart("members");
+        arrayStart();
+        for (size_t i = 0; i < d->members->dim; i++)
+        {
+            Dsymbol *s = (*d->members)[i];
+            s->accept(this);
+        }
+        arrayEnd();
+
+        objectEnd();
+    }
+
+    void visit(EnumDeclaration *d)
+    {
+        if (d->isAnonymous())
+        {
+            if (d->members)
+            {
+                for (size_t i = 0; i < d->members->dim; i++)
+                {
+                    Dsymbol *s = (*d->members)[i];
+                    s->accept(this);
+                }
+            }
+            return;
+        }
+
+        objectStart();
+
+        jsonProperties(d);
+
+        property("base", "baseDeco", d->memtype);
+
+        if (d->members)
+        {
+            propertyStart("members");
+            arrayStart();
+            for (size_t i = 0; i < d->members->dim; i++)
+            {
+                Dsymbol *s = (*d->members)[i];
+                s->accept(this);
+            }
+            arrayEnd();
+        }
+
+        objectEnd();
+    }
+
+    void visit(EnumMember *s)
+    {
+        objectStart();
+
+        jsonProperties((Dsymbol*)s);
+
+        property("type", "deco", s->origType);
+
+        objectEnd();
+    }
+
+    void visit(VarDeclaration *d)
+    {
+        objectStart();
+
+        jsonProperties(d);
+
+        if (d->_init)
+            property("init", d->_init->toChars());
+
+        if (d->isField())
+            property("offset", d->offset);
+
+        if (d->alignment && d->alignment != STRUCTALIGN_DEFAULT)
+            property("align", d->alignment);
+
+        objectEnd();
+    }
+
+    void visit(TemplateMixin *d)
+    {
+        objectStart();
+
+        jsonProperties(d);
+
+        objectEnd();
+    }
+};
+
+
+void json_generate(OutBuffer *buf, Modules *modules)
+{
+    ToJsonVisitor json(buf);
+
+    json.arrayStart();
+    for (size_t i = 0; i < modules->dim; i++)
+    {
+        Module *m = (*modules)[i];
+        if (global.params.verbose)
+            fprintf(global.stdmsg, "json gen %s\n", m->toChars());
+        m->accept(&json);
+    }
+    json.arrayEnd();
+    json.removeComma();
+}
diff --git a/gcc/d/dfrontend/json.h b/gcc/d/dfrontend/json.h
new file mode 100644
index 00000000000..ef59a947f35
--- /dev/null
+++ b/gcc/d/dfrontend/json.h
@@ -0,0 +1,26 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/json.h
+ */
+
+#ifndef DMD_JSON_H
+#define DMD_JSON_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "arraytypes.h"
+
+struct OutBuffer;
+
+void json_generate(OutBuffer *, Modules *);
+
+#endif /* DMD_JSON_H */
+
diff --git a/gcc/d/dfrontend/lexer.c b/gcc/d/dfrontend/lexer.c
new file mode 100644
index 00000000000..b17d6e38542
--- /dev/null
+++ b/gcc/d/dfrontend/lexer.c
@@ -0,0 +1,2424 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/lexer.c
+ */
+
+/* Lexical Analyzer */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <time.h>       // for time() and ctime()
+
+#include "rmem.h"
+
+#include "lexer.h"
+#include "utf.h"
+#include "identifier.h"
+#include "id.h"
+
+extern int HtmlNamedEntity(const utf8_t *p, size_t length);
+
+#define LS 0x2028       // UTF line separator
+#define PS 0x2029       // UTF paragraph separator
+
+/********************************************
+ * Do our own char maps
+ */
+
+static unsigned char cmtable[256];
+
+const int CMoctal =     0x1;
+const int CMhex =       0x2;
+const int CMidchar =    0x4;
+
+inline bool isoctal (utf8_t c) { return (cmtable[c] & CMoctal) != 0; }
+inline bool ishex   (utf8_t c) { return (cmtable[c] & CMhex) != 0; }
+inline bool isidchar(utf8_t c) { return (cmtable[c] & CMidchar) != 0; }
+
+struct CMTableInitializer
+{
+    CMTableInitializer();
+};
+
+static CMTableInitializer cmtableinitializer;
+
+CMTableInitializer::CMTableInitializer()
+{
+    for (unsigned c = 0; c < 256; c++)
+    {
+        if ('0' <= c && c <= '7')
+            cmtable[c] |= CMoctal;
+        if (isxdigit(c))
+            cmtable[c] |= CMhex;
+        if (isalnum(c) || c == '_')
+            cmtable[c] |= CMidchar;
+    }
+}
+
+/*************************** Lexer ********************************************/
+
+OutBuffer Lexer::stringbuffer;
+
+Lexer::Lexer(const char *filename,
+        const utf8_t *base, size_t begoffset, size_t endoffset,
+        bool doDocComment, bool commentToken)
+{
+    scanloc = Loc(filename, 1, 1);
+    //printf("Lexer::Lexer(%p,%d)\n",base,length);
+    //printf("lexer.filename = %s\n", filename);
+    memset(&token,0,sizeof(token));
+    this->base = base;
+    this->end  = base + endoffset;
+    p = base + begoffset;
+    line = p;
+    this->doDocComment = doDocComment;
+    this->anyToken = 0;
+    this->commentToken = commentToken;
+    this->errors = false;
+    //initKeywords();
+
+    /* If first line starts with '#!', ignore the line
+     */
+
+    if (p[0] == '#' && p[1] =='!')
+    {
+        p += 2;
+        while (1)
+        {   utf8_t c = *p;
+            switch (c)
+            {
+                case '\n':
+                    p++;
+                    break;
+
+                case '\r':
+                    p++;
+                    if (*p == '\n')
+                        p++;
+                    break;
+
+                case 0:
+                case 0x1A:
+                    break;
+
+                default:
+                    if (c & 0x80)
+                    {   unsigned u = decodeUTF();
+                        if (u == PS || u == LS)
+                            break;
+                    }
+                    p++;
+                    continue;
+            }
+            break;
+        }
+        endOfLine();
+    }
+}
+
+
+void Lexer::endOfLine()
+{
+    scanloc.linnum++;
+    line = p;
+}
+
+
+void Lexer::error(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::verror(token.loc, format, ap);
+    va_end(ap);
+    errors = true;
+}
+
+void Lexer::error(Loc loc, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::verror(loc, format, ap);
+    va_end(ap);
+    errors = true;
+}
+
+void Lexer::deprecation(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::vdeprecation(token.loc, format, ap);
+    va_end(ap);
+    if (global.params.useDeprecated == 0)
+        errors = true;
+}
+
+TOK Lexer::nextToken()
+{
+    if (token.next)
+    {
+        Token *t = token.next;
+        memcpy(&token,t,sizeof(Token));
+        t->free();
+    }
+    else
+    {
+        scan(&token);
+    }
+    //token.print();
+    return token.value;
+}
+
+Token *Lexer::peek(Token *ct)
+{
+    Token *t;
+    if (ct->next)
+        t = ct->next;
+    else
+    {
+        t = Token::alloc();
+        scan(t);
+        ct->next = t;
+    }
+    return t;
+}
+
+/***********************
+ * Look ahead at next token's value.
+ */
+
+TOK Lexer::peekNext()
+{
+    return peek(&token)->value;
+}
+
+/***********************
+ * Look 2 tokens ahead at value.
+ */
+
+TOK Lexer::peekNext2()
+{
+    Token *t = peek(&token);
+    return peek(t)->value;
+}
+
+/*********************************
+ * tk is on the opening (.
+ * Look ahead and return token that is past the closing ).
+ */
+
+Token *Lexer::peekPastParen(Token *tk)
+{
+    //printf("peekPastParen()\n");
+    int parens = 1;
+    int curlynest = 0;
+    while (1)
+    {
+        tk = peek(tk);
+        //tk->print();
+        switch (tk->value)
+        {
+            case TOKlparen:
+                parens++;
+                continue;
+
+            case TOKrparen:
+                --parens;
+                if (parens)
+                    continue;
+                tk = peek(tk);
+                break;
+
+            case TOKlcurly:
+                curlynest++;
+                continue;
+
+            case TOKrcurly:
+                if (--curlynest >= 0)
+                    continue;
+                break;
+
+            case TOKsemicolon:
+                if (curlynest)
+                    continue;
+                break;
+
+            case TOKeof:
+                break;
+
+            default:
+                continue;
+        }
+        return tk;
+    }
+}
+
+/****************************
+ * Turn next token in buffer into a token.
+ */
+
+void Lexer::scan(Token *t)
+{
+    unsigned lastLine = scanloc.linnum;
+    Loc startLoc;
+
+    t->blockComment = NULL;
+    t->lineComment = NULL;
+    while (1)
+    {
+        t->ptr = p;
+        //printf("p = %p, *p = '%c'\n",p,*p);
+        t->loc = loc();
+        switch (*p)
+        {
+            case 0:
+            case 0x1A:
+                t->value = TOKeof;                      // end of file
+                return;
+
+            case ' ':
+            case '\t':
+            case '\v':
+            case '\f':
+                p++;
+                continue;                       // skip white space
+
+            case '\r':
+                p++;
+                if (*p != '\n')                 // if CR stands by itself
+                    endOfLine();
+                continue;                       // skip white space
+
+            case '\n':
+                p++;
+                endOfLine();
+                continue;                       // skip white space
+
+            case '0':   case '1':   case '2':   case '3':   case '4':
+            case '5':   case '6':   case '7':   case '8':   case '9':
+                t->value = number(t);
+                return;
+
+            case '\'':
+                t->value = charConstant(t,0);
+                return;
+
+            case 'r':
+                if (p[1] != '"')
+                    goto case_ident;
+                p++;
+            case '`':
+                t->value = wysiwygStringConstant(t, *p);
+                return;
+
+            case 'x':
+                if (p[1] != '"')
+                    goto case_ident;
+                p++;
+                t->value = hexStringConstant(t);
+                return;
+
+            case 'q':
+                if (p[1] == '"')
+                {
+                    p++;
+                    t->value = delimitedStringConstant(t);
+                    return;
+                }
+                else if (p[1] == '{')
+                {
+                    p++;
+                    t->value = tokenStringConstant(t);
+                    return;
+                }
+                else
+                    goto case_ident;
+
+            case '"':
+                t->value = escapeStringConstant(t,0);
+                return;
+
+            case 'a':   case 'b':   case 'c':   case 'd':   case 'e':
+            case 'f':   case 'g':   case 'h':   case 'i':   case 'j':
+            case 'k':   case 'l':   case 'm':   case 'n':   case 'o':
+            case 'p':   /*case 'q': case 'r':*/ case 's':   case 't':
+            case 'u':   case 'v':   case 'w': /*case 'x':*/ case 'y':
+            case 'z':
+            case 'A':   case 'B':   case 'C':   case 'D':   case 'E':
+            case 'F':   case 'G':   case 'H':   case 'I':   case 'J':
+            case 'K':   case 'L':   case 'M':   case 'N':   case 'O':
+            case 'P':   case 'Q':   case 'R':   case 'S':   case 'T':
+            case 'U':   case 'V':   case 'W':   case 'X':   case 'Y':
+            case 'Z':
+            case '_':
+            case_ident:
+            {   utf8_t c;
+
+                while (1)
+                {
+                    c = *++p;
+                    if (isidchar(c))
+                        continue;
+                    else if (c & 0x80)
+                    {   const utf8_t *s = p;
+                        unsigned u = decodeUTF();
+                        if (isUniAlpha(u))
+                            continue;
+                        error("char 0x%04x not allowed in identifier", u);
+                        p = s;
+                    }
+                    break;
+                }
+
+                Identifier *id = Identifier::idPool((char *)t->ptr, p - t->ptr);
+                t->ident = id;
+                t->value = (TOK) id->getValue();
+                anyToken = 1;
+                if (*t->ptr == '_')     // if special identifier token
+                {
+                    static bool initdone = false;
+                    static char date[11+1];
+                    static char time[8+1];
+                    static char timestamp[24+1];
+
+                    if (!initdone)       // lazy evaluation
+                    {
+                        initdone = true;
+                        time_t ct;
+                        ::time(&ct);
+                        char *p = ctime(&ct);
+                        assert(p);
+                        sprintf(&date[0], "%.6s %.4s", p + 4, p + 20);
+                        sprintf(&time[0], "%.8s", p + 11);
+                        sprintf(&timestamp[0], "%.24s", p);
+                    }
+
+                    if (id == Id::DATE)
+                    {
+                        t->ustring = (utf8_t *)date;
+                        goto Lstr;
+                    }
+                    else if (id == Id::TIME)
+                    {
+                        t->ustring = (utf8_t *)time;
+                        goto Lstr;
+                    }
+                    else if (id == Id::VENDOR)
+                    {
+                        t->ustring = (utf8_t *)global.compiler.vendor;
+                        goto Lstr;
+                    }
+                    else if (id == Id::TIMESTAMP)
+                    {
+                        t->ustring = (utf8_t *)timestamp;
+                     Lstr:
+                        t->value = TOKstring;
+                        t->postfix = 0;
+                        t->len = (unsigned)strlen((char *)t->ustring);
+                    }
+                    else if (id == Id::VERSIONX)
+                    {   unsigned major = 0;
+                        unsigned minor = 0;
+                        bool point = false;
+
+                        for (const char *p = global.version + 1; 1; p++)
+                        {
+                            c = *p;
+                            if (isdigit((utf8_t)c))
+                                minor = minor * 10 + c - '0';
+                            else if (c == '.')
+                            {
+                                if (point)
+                                    break;      // ignore everything after second '.'
+                                point = true;
+                                major = minor;
+                                minor = 0;
+                            }
+                            else
+                                break;
+                        }
+                        t->value = TOKint64v;
+                        t->uns64value = major * 1000 + minor;
+                    }
+                    else if (id == Id::EOFX)
+                    {
+                        t->value = TOKeof;
+                        // Advance scanner to end of file
+                        while (!(*p == 0 || *p == 0x1A))
+                            p++;
+                    }
+                }
+                //printf("t->value = %d\n",t->value);
+                return;
+            }
+
+            case '/':
+                p++;
+                switch (*p)
+                {
+                    case '=':
+                        p++;
+                        t->value = TOKdivass;
+                        return;
+
+                    case '*':
+                        p++;
+                        startLoc = loc();
+                        while (1)
+                        {
+                            while (1)
+                            {   utf8_t c = *p;
+                                switch (c)
+                                {
+                                    case '/':
+                                        break;
+
+                                    case '\n':
+                                        endOfLine();
+                                        p++;
+                                        continue;
+
+                                    case '\r':
+                                        p++;
+                                        if (*p != '\n')
+                                            endOfLine();
+                                        continue;
+
+                                    case 0:
+                                    case 0x1A:
+                                        error("unterminated /* */ comment");
+                                        p = end;
+                                        t->loc = loc();
+                                        t->value = TOKeof;
+                                        return;
+
+                                    default:
+                                        if (c & 0x80)
+                                        {   unsigned u = decodeUTF();
+                                            if (u == PS || u == LS)
+                                                endOfLine();
+                                        }
+                                        p++;
+                                        continue;
+                                }
+                                break;
+                            }
+                            p++;
+                            if (p[-2] == '*' && p - 3 != t->ptr)
+                                break;
+                        }
+                        if (commentToken)
+                        {
+                            t->loc = startLoc;
+                            t->value = TOKcomment;
+                            return;
+                        }
+                        else if (doDocComment && t->ptr[2] == '*' && p - 4 != t->ptr)
+                        {   // if /** but not /**/
+                            getDocComment(t, lastLine == startLoc.linnum);
+                        }
+                        continue;
+
+                    case '/':           // do // style comments
+                        startLoc = loc();
+                        while (1)
+                        {   utf8_t c = *++p;
+                            switch (c)
+                            {
+                                case '\n':
+                                    break;
+
+                                case '\r':
+                                    if (p[1] == '\n')
+                                        p++;
+                                    break;
+
+                                case 0:
+                                case 0x1A:
+                                    if (commentToken)
+                                    {
+                                        p = end;
+                                        t->loc = startLoc;
+                                        t->value = TOKcomment;
+                                        return;
+                                    }
+                                    if (doDocComment && t->ptr[2] == '/')
+                                        getDocComment(t, lastLine == startLoc.linnum);
+                                    p = end;
+                                    t->loc = loc();
+                                    t->value = TOKeof;
+                                    return;
+
+                                default:
+                                    if (c & 0x80)
+                                    {   unsigned u = decodeUTF();
+                                        if (u == PS || u == LS)
+                                            break;
+                                    }
+                                    continue;
+                            }
+                            break;
+                        }
+
+                        if (commentToken)
+                        {
+                            p++;
+                            endOfLine();
+                            t->loc = startLoc;
+                            t->value = TOKcomment;
+                            return;
+                        }
+                        if (doDocComment && t->ptr[2] == '/')
+                            getDocComment(t, lastLine == startLoc.linnum);
+
+                        p++;
+                        endOfLine();
+                        continue;
+
+                    case '+':
+                    {   int nest;
+
+                        startLoc = loc();
+                        p++;
+                        nest = 1;
+                        while (1)
+                        {   utf8_t c = *p;
+                            switch (c)
+                            {
+                                case '/':
+                                    p++;
+                                    if (*p == '+')
+                                    {
+                                        p++;
+                                        nest++;
+                                    }
+                                    continue;
+
+                                case '+':
+                                    p++;
+                                    if (*p == '/')
+                                    {
+                                        p++;
+                                        if (--nest == 0)
+                                            break;
+                                    }
+                                    continue;
+
+                                case '\r':
+                                    p++;
+                                    if (*p != '\n')
+                                        endOfLine();
+                                    continue;
+
+                                case '\n':
+                                    endOfLine();
+                                    p++;
+                                    continue;
+
+                                case 0:
+                                case 0x1A:
+                                    error("unterminated /+ +/ comment");
+                                    p = end;
+                                    t->loc = loc();
+                                    t->value = TOKeof;
+                                    return;
+
+                                default:
+                                    if (c & 0x80)
+                                    {   unsigned u = decodeUTF();
+                                        if (u == PS || u == LS)
+                                            endOfLine();
+                                    }
+                                    p++;
+                                    continue;
+                            }
+                            break;
+                        }
+                        if (commentToken)
+                        {
+                            t->loc = startLoc;
+                            t->value = TOKcomment;
+                            return;
+                        }
+                        if (doDocComment && t->ptr[2] == '+' && p - 4 != t->ptr)
+                        {   // if /++ but not /++/
+                            getDocComment(t, lastLine == startLoc.linnum);
+                        }
+                        continue;
+                    }
+                    default:
+                        break;
+                }
+                t->value = TOKdiv;
+                return;
+
+            case '.':
+                p++;
+                if (isdigit(*p))
+                {   /* Note that we don't allow ._1 and ._ as being
+                     * valid floating point numbers.
+                     */
+                    p--;
+                    t->value = inreal(t);
+                }
+                else if (p[0] == '.')
+                {
+                    if (p[1] == '.')
+                    {   p += 2;
+                        t->value = TOKdotdotdot;
+                    }
+                    else
+                    {   p++;
+                        t->value = TOKslice;
+                    }
+                }
+                else
+                    t->value = TOKdot;
+                return;
+
+            case '&':
+                p++;
+                if (*p == '=')
+                {   p++;
+                    t->value = TOKandass;
+                }
+                else if (*p == '&')
+                {   p++;
+                    t->value = TOKandand;
+                }
+                else
+                    t->value = TOKand;
+                return;
+
+            case '|':
+                p++;
+                if (*p == '=')
+                {   p++;
+                    t->value = TOKorass;
+                }
+                else if (*p == '|')
+                {   p++;
+                    t->value = TOKoror;
+                }
+                else
+                    t->value = TOKor;
+                return;
+
+            case '-':
+                p++;
+                if (*p == '=')
+                {   p++;
+                    t->value = TOKminass;
+                }
+                else if (*p == '-')
+                {   p++;
+                    t->value = TOKminusminus;
+                }
+                else
+                    t->value = TOKmin;
+                return;
+
+            case '+':
+                p++;
+                if (*p == '=')
+                {   p++;
+                    t->value = TOKaddass;
+                }
+                else if (*p == '+')
+                {   p++;
+                    t->value = TOKplusplus;
+                }
+                else
+                    t->value = TOKadd;
+                return;
+
+            case '<':
+                p++;
+                if (*p == '=')
+                {   p++;
+                    t->value = TOKle;                   // <=
+                }
+                else if (*p == '<')
+                {   p++;
+                    if (*p == '=')
+                    {   p++;
+                        t->value = TOKshlass;           // <<=
+                    }
+                    else
+                        t->value = TOKshl;              // <<
+                }
+                else if (*p == '>')
+                {   p++;
+                    if (*p == '=')
+                    {   p++;
+                        t->value = TOKleg;              // <>=
+                    }
+                    else
+                        t->value = TOKlg;               // <>
+                }
+                else
+                    t->value = TOKlt;                   // <
+                return;
+
+            case '>':
+                p++;
+                if (*p == '=')
+                {   p++;
+                    t->value = TOKge;                   // >=
+                }
+                else if (*p == '>')
+                {   p++;
+                    if (*p == '=')
+                    {   p++;
+                        t->value = TOKshrass;           // >>=
+                    }
+                    else if (*p == '>')
+                    {   p++;
+                        if (*p == '=')
+                        {   p++;
+                            t->value = TOKushrass;      // >>>=
+                        }
+                        else
+                            t->value = TOKushr;         // >>>
+                    }
+                    else
+                        t->value = TOKshr;              // >>
+                }
+                else
+                    t->value = TOKgt;                   // >
+                return;
+
+            case '!':
+                p++;
+                if (*p == '=')
+                {   p++;
+                    t->value = TOKnotequal;         // !=
+                }
+                else if (*p == '<')
+                {   p++;
+                    if (*p == '>')
+                    {   p++;
+                        if (*p == '=')
+                        {   p++;
+                            t->value = TOKunord; // !<>=
+                        }
+                        else
+                            t->value = TOKue;   // !<>
+                    }
+                    else if (*p == '=')
+                    {   p++;
+                        t->value = TOKug;       // !<=
+                    }
+                    else
+                        t->value = TOKuge;      // !<
+                }
+                else if (*p == '>')
+                {   p++;
+                    if (*p == '=')
+                    {   p++;
+                        t->value = TOKul;       // !>=
+                    }
+                    else
+                        t->value = TOKule;      // !>
+                }
+                else
+                    t->value = TOKnot;          // !
+                return;
+
+            case '=':
+                p++;
+                if (*p == '=')
+                {   p++;
+                    t->value = TOKequal;            // ==
+                }
+                else if (*p == '>')
+                {   p++;
+                    t->value = TOKgoesto;               // =>
+                }
+                else
+                    t->value = TOKassign;               // =
+                return;
+
+            case '~':
+                p++;
+                if (*p == '=')
+                {   p++;
+                    t->value = TOKcatass;               // ~=
+                }
+                else
+                    t->value = TOKtilde;                // ~
+                return;
+
+            case '^':
+                p++;
+                if (*p == '^')
+                {   p++;
+                    if (*p == '=')
+                    {   p++;
+                        t->value = TOKpowass;  // ^^=
+                    }
+                    else
+                        t->value = TOKpow;     // ^^
+                }
+                else if (*p == '=')
+                {   p++;
+                    t->value = TOKxorass;    // ^=
+                }
+                else
+                    t->value = TOKxor;       // ^
+                return;
+
+            case '(': p++; t->value = TOKlparen; return;
+            case ')': p++; t->value = TOKrparen; return;
+            case '[': p++; t->value = TOKlbracket; return;
+            case ']': p++; t->value = TOKrbracket; return;
+            case '{': p++; t->value = TOKlcurly; return;
+            case '}': p++; t->value = TOKrcurly; return;
+            case '?': p++; t->value = TOKquestion; return;
+            case ',': p++; t->value = TOKcomma; return;
+            case ';': p++; t->value = TOKsemicolon; return;
+            case ':': p++; t->value = TOKcolon; return;
+            case '$': p++; t->value = TOKdollar; return;
+            case '@': p++; t->value = TOKat; return;
+
+            case '*':
+                p++;
+                if (*p == '=')
+                {   p++;
+                    t->value = TOKmulass;
+                }
+                else
+                    t->value = TOKmul;
+                return;
+            case '%':
+                p++;
+                if (*p == '=')
+                {   p++;
+                    t->value = TOKmodass;
+                }
+                else
+                    t->value = TOKmod;
+                return;
+
+            case '#':
+            {
+                p++;
+                Token n;
+                scan(&n);
+                if (n.value == TOKidentifier && n.ident == Id::line)
+                {
+                    poundLine();
+                    continue;
+                }
+                else
+                {
+                    t->value = TOKpound;
+                    return;
+                }
+            }
+
+            default:
+            {   unsigned c = *p;
+
+                if (c & 0x80)
+                {   c = decodeUTF();
+
+                    // Check for start of unicode identifier
+                    if (isUniAlpha(c))
+                        goto case_ident;
+
+                    if (c == PS || c == LS)
+                    {
+                        endOfLine();
+                        p++;
+                        continue;
+                    }
+                }
+                if (c < 0x80 && isprint(c))
+                    error("character '%c' is not a valid token", c);
+                else
+                    error("character 0x%02x is not a valid token", c);
+                p++;
+                continue;
+            }
+        }
+    }
+}
+
+/*******************************************
+ * Parse escape sequence.
+ */
+
+unsigned Lexer::escapeSequence()
+{   unsigned c = *p;
+
+    int n;
+    int ndigits;
+
+    switch (c)
+    {
+        case '\'':
+        case '"':
+        case '?':
+        case '\\':
+        Lconsume:
+                p++;
+                break;
+
+        case 'a':       c = 7;          goto Lconsume;
+        case 'b':       c = 8;          goto Lconsume;
+        case 'f':       c = 12;         goto Lconsume;
+        case 'n':       c = 10;         goto Lconsume;
+        case 'r':       c = 13;         goto Lconsume;
+        case 't':       c = 9;          goto Lconsume;
+        case 'v':       c = 11;         goto Lconsume;
+
+        case 'u':
+                ndigits = 4;
+                goto Lhex;
+        case 'U':
+                ndigits = 8;
+                goto Lhex;
+        case 'x':
+                ndigits = 2;
+        Lhex:
+                p++;
+                c = *p;
+                if (ishex((utf8_t)c))
+                {   unsigned v;
+
+                    n = 0;
+                    v = 0;
+                    while (1)
+                    {
+                        if (isdigit((utf8_t)c))
+                            c -= '0';
+                        else if (islower(c))
+                            c -= 'a' - 10;
+                        else
+                            c -= 'A' - 10;
+                        v = v * 16 + c;
+                        c = *++p;
+                        if (++n == ndigits)
+                            break;
+                        if (!ishex((utf8_t)c))
+                        {   error("escape hex sequence has %d hex digits instead of %d", n, ndigits);
+                            break;
+                        }
+                    }
+                    if (ndigits != 2 && !utf_isValidDchar(v))
+                    {   error("invalid UTF character \\U%08x", v);
+                        v = '?';        // recover with valid UTF character
+                    }
+                    c = v;
+                }
+                else
+                    error("undefined escape hex sequence \\%c",c);
+                break;
+
+        case '&':                       // named character entity
+                for (const utf8_t *idstart = ++p; 1; p++)
+                {
+                    switch (*p)
+                    {
+                        case ';':
+                            c = HtmlNamedEntity(idstart, p - idstart);
+                            if (c == ~0)
+                            {   error("unnamed character entity &%.*s;", (int)(p - idstart), idstart);
+                                c = ' ';
+                            }
+                            p++;
+                            break;
+
+                        default:
+                            if (isalpha(*p) ||
+                                (p != idstart && isdigit(*p)))
+                                continue;
+                            error("unterminated named entity &%.*s;", (int)(p - idstart + 1), idstart);
+                            break;
+                    }
+                    break;
+                }
+                break;
+
+        case 0:
+        case 0x1A:                      // end of file
+                c = '\\';
+                break;
+
+        default:
+                if (isoctal((utf8_t)c))
+                {   unsigned v;
+
+                    n = 0;
+                    v = 0;
+                    do
+                    {
+                        v = v * 8 + (c - '0');
+                        c = *++p;
+                    } while (++n < 3 && isoctal((utf8_t)c));
+                    c = v;
+                    if (c > 0xFF)
+                        error("escape octal sequence \\%03o is larger than \\377", c);
+                }
+                else
+                    error("undefined escape sequence \\%c",c);
+                break;
+    }
+    return c;
+}
+
+/**************************************
+ */
+
+TOK Lexer::wysiwygStringConstant(Token *t, int tc)
+{
+    unsigned c;
+    Loc start = loc();
+
+    p++;
+    stringbuffer.reset();
+    while (1)
+    {
+        c = *p++;
+        switch (c)
+        {
+            case '\n':
+                endOfLine();
+                break;
+
+            case '\r':
+                if (*p == '\n')
+                    continue;   // ignore
+                c = '\n';       // treat EndOfLine as \n character
+                endOfLine();
+                break;
+
+            case 0:
+            case 0x1A:
+                error("unterminated string constant starting at %s", start.toChars());
+                t->ustring = (utf8_t *)"";
+                t->len = 0;
+                t->postfix = 0;
+                return TOKstring;
+
+            case '"':
+            case '`':
+                if (c == tc)
+                {
+                    t->len = (unsigned)stringbuffer.offset;
+                    stringbuffer.writeByte(0);
+                    t->ustring = (utf8_t *)mem.xmalloc(stringbuffer.offset);
+                    memcpy(t->ustring, stringbuffer.data, stringbuffer.offset);
+                    stringPostfix(t);
+                    return TOKstring;
+                }
+                break;
+
+            default:
+                if (c & 0x80)
+                {   p--;
+                    unsigned u = decodeUTF();
+                    p++;
+                    if (u == PS || u == LS)
+                        endOfLine();
+                    stringbuffer.writeUTF8(u);
+                    continue;
+                }
+                break;
+        }
+        stringbuffer.writeByte(c);
+    }
+}
+
+/**************************************
+ * Lex hex strings:
+ *      x"0A ae 34FE BD"
+ */
+
+TOK Lexer::hexStringConstant(Token *t)
+{
+    unsigned c;
+    Loc start = loc();
+    unsigned n = 0;
+    unsigned v = ~0; // dead assignment, needed to suppress warning
+
+    p++;
+    stringbuffer.reset();
+    while (1)
+    {
+        c = *p++;
+        switch (c)
+        {
+            case ' ':
+            case '\t':
+            case '\v':
+            case '\f':
+                continue;                       // skip white space
+
+            case '\r':
+                if (*p == '\n')
+                    continue;                   // ignore
+                // Treat isolated '\r' as if it were a '\n'
+            case '\n':
+                endOfLine();
+                continue;
+
+            case 0:
+            case 0x1A:
+                error("unterminated string constant starting at %s", start.toChars());
+                t->ustring = (utf8_t *)"";
+                t->len = 0;
+                t->postfix = 0;
+                return TOKxstring;
+
+            case '"':
+                if (n & 1)
+                {   error("odd number (%d) of hex characters in hex string", n);
+                    stringbuffer.writeByte(v);
+                }
+                t->len = (unsigned)stringbuffer.offset;
+                stringbuffer.writeByte(0);
+                t->ustring = (utf8_t *)mem.xmalloc(stringbuffer.offset);
+                memcpy(t->ustring, stringbuffer.data, stringbuffer.offset);
+                stringPostfix(t);
+                return TOKxstring;
+
+            default:
+                if (c >= '0' && c <= '9')
+                    c -= '0';
+                else if (c >= 'a' && c <= 'f')
+                    c -= 'a' - 10;
+                else if (c >= 'A' && c <= 'F')
+                    c -= 'A' - 10;
+                else if (c & 0x80)
+                {   p--;
+                    unsigned u = decodeUTF();
+                    p++;
+                    if (u == PS || u == LS)
+                        endOfLine();
+                    else
+                        error("non-hex character \\u%04x in hex string", u);
+                }
+                else
+                    error("non-hex character '%c' in hex string", c);
+                if (n & 1)
+                {   v = (v << 4) | c;
+                    stringbuffer.writeByte(v);
+                }
+                else
+                    v = c;
+                n++;
+                break;
+        }
+    }
+}
+
+
+/**************************************
+ * Lex delimited strings:
+ *      q"(foo(xxx))"   // "foo(xxx)"
+ *      q"[foo(]"       // "foo("
+ *      q"/foo]/"       // "foo]"
+ *      q"HERE
+ *      foo
+ *      HERE"           // "foo\n"
+ * Input:
+ *      p is on the "
+ */
+
+TOK Lexer::delimitedStringConstant(Token *t)
+{
+    unsigned c;
+    Loc start = loc();
+    unsigned delimleft = 0;
+    unsigned delimright = 0;
+    unsigned nest = 1;
+    unsigned nestcount = ~0; // dead assignment, needed to suppress warning
+    Identifier *hereid = NULL;
+    unsigned blankrol = 0;
+    unsigned startline = 0;
+
+    p++;
+    stringbuffer.reset();
+    while (1)
+    {
+        c = *p++;
+        //printf("c = '%c'\n", c);
+        switch (c)
+        {
+            case '\n':
+            Lnextline:
+                endOfLine();
+                startline = 1;
+                if (blankrol)
+                {   blankrol = 0;
+                    continue;
+                }
+                if (hereid)
+                {
+                    stringbuffer.writeUTF8(c);
+                    continue;
+                }
+                break;
+
+            case '\r':
+                if (*p == '\n')
+                    continue;   // ignore
+                c = '\n';       // treat EndOfLine as \n character
+                goto Lnextline;
+
+            case 0:
+            case 0x1A:
+                error("unterminated delimited string constant starting at %s", start.toChars());
+                t->ustring = (utf8_t *)"";
+                t->len = 0;
+                t->postfix = 0;
+                return TOKstring;
+
+            default:
+                if (c & 0x80)
+                {   p--;
+                    c = decodeUTF();
+                    p++;
+                    if (c == PS || c == LS)
+                        goto Lnextline;
+                }
+                break;
+        }
+        if (delimleft == 0)
+        {   delimleft = c;
+            nest = 1;
+            nestcount = 1;
+            if (c == '(')
+                delimright = ')';
+            else if (c == '{')
+                delimright = '}';
+            else if (c == '[')
+                delimright = ']';
+            else if (c == '<')
+                delimright = '>';
+            else if (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c)))
+            {   // Start of identifier; must be a heredoc
+                Token tok;
+                p--;
+                scan(&tok);               // read in heredoc identifier
+                if (tok.value != TOKidentifier)
+                {   error("identifier expected for heredoc, not %s", tok.toChars());
+                    delimright = c;
+                }
+                else
+                {   hereid = tok.ident;
+                    //printf("hereid = '%s'\n", hereid->toChars());
+                    blankrol = 1;
+                }
+                nest = 0;
+            }
+            else
+            {   delimright = c;
+                nest = 0;
+                if (isspace(c))
+                    error("delimiter cannot be whitespace");
+            }
+        }
+        else
+        {
+            if (blankrol)
+            {   error("heredoc rest of line should be blank");
+                blankrol = 0;
+                continue;
+            }
+            if (nest == 1)
+            {
+                if (c == delimleft)
+                    nestcount++;
+                else if (c == delimright)
+                {   nestcount--;
+                    if (nestcount == 0)
+                        goto Ldone;
+                }
+            }
+            else if (c == delimright)
+                goto Ldone;
+            if (startline && isalpha(c) && hereid)
+            {   Token tok;
+                const utf8_t *psave = p;
+                p--;
+                scan(&tok);               // read in possible heredoc identifier
+                //printf("endid = '%s'\n", tok.ident->toChars());
+                if (tok.value == TOKidentifier && tok.ident->equals(hereid))
+                {   /* should check that rest of line is blank
+                     */
+                    goto Ldone;
+                }
+                p = psave;
+            }
+            stringbuffer.writeUTF8(c);
+            startline = 0;
+        }
+    }
+
+Ldone:
+    if (*p == '"')
+        p++;
+    else if (hereid)
+        error("delimited string must end in %s\"", hereid->toChars());
+    else
+        error("delimited string must end in %c\"", delimright);
+    t->len = (unsigned)stringbuffer.offset;
+    stringbuffer.writeByte(0);
+    t->ustring = (utf8_t *)mem.xmalloc(stringbuffer.offset);
+    memcpy(t->ustring, stringbuffer.data, stringbuffer.offset);
+    stringPostfix(t);
+    return TOKstring;
+}
+
+/**************************************
+ * Lex delimited strings:
+ *      q{ foo(xxx) } // " foo(xxx) "
+ *      q{foo(}       // "foo("
+ *      q{{foo}"}"}   // "{foo}"}""
+ * Input:
+ *      p is on the q
+ */
+
+TOK Lexer::tokenStringConstant(Token *t)
+{
+    unsigned nest = 1;
+    Loc start = loc();
+    const utf8_t *pstart = ++p;
+
+    while (1)
+    {   Token tok;
+
+        scan(&tok);
+        switch (tok.value)
+        {
+            case TOKlcurly:
+                nest++;
+                continue;
+
+            case TOKrcurly:
+                if (--nest == 0)
+                {
+                    t->len = (unsigned)(p - 1 - pstart);
+                    t->ustring = (utf8_t *)mem.xmalloc(t->len + 1);
+                    memcpy(t->ustring, pstart, t->len);
+                    t->ustring[t->len] = 0;
+                    stringPostfix(t);
+                    return TOKstring;
+                }
+                continue;
+
+            case TOKeof:
+                error("unterminated token string constant starting at %s", start.toChars());
+                t->ustring = (utf8_t *)"";
+                t->len = 0;
+                t->postfix = 0;
+                return TOKstring;
+
+            default:
+                continue;
+        }
+    }
+}
+
+
+
+/**************************************
+ */
+
+TOK Lexer::escapeStringConstant(Token *t, int wide)
+{
+    unsigned c;
+    Loc start = loc();
+
+    p++;
+    stringbuffer.reset();
+    while (1)
+    {
+        c = *p++;
+        switch (c)
+        {
+            case '\\':
+                switch (*p)
+                {
+                    case 'u':
+                    case 'U':
+                    case '&':
+                        c = escapeSequence();
+                        stringbuffer.writeUTF8(c);
+                        continue;
+
+                    default:
+                        c = escapeSequence();
+                        break;
+                }
+                break;
+            case '\n':
+                endOfLine();
+                break;
+
+            case '\r':
+                if (*p == '\n')
+                    continue;   // ignore
+                c = '\n';       // treat EndOfLine as \n character
+                endOfLine();
+                break;
+
+            case '"':
+                t->len = (unsigned)stringbuffer.offset;
+                stringbuffer.writeByte(0);
+                t->ustring = (utf8_t *)mem.xmalloc(stringbuffer.offset);
+                memcpy(t->ustring, stringbuffer.data, stringbuffer.offset);
+                stringPostfix(t);
+                return TOKstring;
+
+            case 0:
+            case 0x1A:
+                p--;
+                error("unterminated string constant starting at %s", start.toChars());
+                t->ustring = (utf8_t *)"";
+                t->len = 0;
+                t->postfix = 0;
+                return TOKstring;
+
+            default:
+                if (c & 0x80)
+                {
+                    p--;
+                    c = decodeUTF();
+                    if (c == LS || c == PS)
+                    {   c = '\n';
+                        endOfLine();
+                    }
+                    p++;
+                    stringbuffer.writeUTF8(c);
+                    continue;
+                }
+                break;
+        }
+        stringbuffer.writeByte(c);
+    }
+}
+
+/**************************************
+ */
+
+TOK Lexer::charConstant(Token *t, int wide)
+{
+    unsigned c;
+    TOK tk = TOKcharv;
+
+    //printf("Lexer::charConstant\n");
+    p++;
+    c = *p++;
+    switch (c)
+    {
+        case '\\':
+            switch (*p)
+            {
+                case 'u':
+                    t->uns64value = escapeSequence();
+                    tk = TOKwcharv;
+                    break;
+
+                case 'U':
+                case '&':
+                    t->uns64value = escapeSequence();
+                    tk = TOKdcharv;
+                    break;
+
+                default:
+                    t->uns64value = escapeSequence();
+                    break;
+            }
+            break;
+        case '\n':
+        L1:
+            endOfLine();
+        case '\r':
+        case 0:
+        case 0x1A:
+        case '\'':
+            error("unterminated character constant");
+            t->uns64value = '?';
+            return tk;
+
+        default:
+            if (c & 0x80)
+            {
+                p--;
+                c = decodeUTF();
+                p++;
+                if (c == LS || c == PS)
+                    goto L1;
+                if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE))
+                    tk = TOKwcharv;
+                else
+                    tk = TOKdcharv;
+            }
+            t->uns64value = c;
+            break;
+    }
+
+    if (*p != '\'')
+    {
+        error("unterminated character constant");
+        t->uns64value = '?';
+        return tk;
+    }
+    p++;
+    return tk;
+}
+
+/***************************************
+ * Get postfix of string literal.
+ */
+
+void Lexer::stringPostfix(Token *t)
+{
+    switch (*p)
+    {
+        case 'c':
+        case 'w':
+        case 'd':
+            t->postfix = *p;
+            p++;
+            break;
+
+        default:
+            t->postfix = 0;
+            break;
+    }
+}
+
+/**************************************
+ * Read in a number.
+ * If it's an integer, store it in tok.TKutok.Vlong.
+ *      integers can be decimal, octal or hex
+ *      Handle the suffixes U, UL, LU, L, etc.
+ * If it's double, store it in tok.TKutok.Vdouble.
+ * Returns:
+ *      TKnum
+ *      TKdouble,...
+ */
+
+TOK Lexer::number(Token *t)
+{
+    int base = 10;
+    const utf8_t *start = p;
+    unsigned c;
+    uinteger_t n = 0;                       // unsigned >=64 bit integer type
+    int d;
+    bool err = false;
+    bool overflow = false;
+
+    c = *p;
+    if (c == '0')
+    {
+        ++p;
+        c = *p;
+        switch (c)
+        {
+            case '0': case '1': case '2': case '3':
+            case '4': case '5': case '6': case '7':
+                n = c - '0';
+                ++p;
+                base = 8;
+                break;
+
+            case 'x':
+            case 'X':
+                ++p;
+                base = 16;
+                break;
+
+            case 'b':
+            case 'B':
+                ++p;
+                base = 2;
+                break;
+
+            case '.':
+                if (p[1] == '.')
+                    goto Ldone; // if ".."
+                if (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80)
+                    goto Ldone; // if ".identifier" or ".unicode"
+                goto Lreal; // '.' is part of current token
+
+            case 'i':
+            case 'f':
+            case 'F':
+                goto Lreal;
+
+            case '_':
+                ++p;
+                base = 8;
+                break;
+
+            case 'L':
+                if (p[1] == 'i')
+                    goto Lreal;
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    while (1)
+    {
+        c = *p;
+        switch (c)
+        {
+            case '0': case '1':
+                ++p;
+                d = c - '0';
+                break;
+
+            case '2': case '3':
+            case '4': case '5': case '6': case '7':
+                if (base == 2 && !err)
+                {
+                    error("binary digit expected");
+                    err = true;
+                }
+                ++p;
+                d = c - '0';
+                break;
+
+            case '8': case '9':
+                ++p;
+                if (base < 10 && !err)
+                {
+                    error("radix %d digit expected, not '%c'", base, c);
+                    err = true;
+                }
+                d = c - '0';
+                break;
+
+            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+                ++p;
+                if (base != 16)
+                {
+                    if (c == 'e' || c == 'E' || c == 'f' || c == 'F')
+                        goto Lreal;
+                    if (!err)
+                    {
+                        error("radix %d digit expected, not '%c'", base, c);
+                        err = true;
+                    }
+                }
+                if (c >= 'a')
+                    d = c + 10 - 'a';
+                else
+                    d = c + 10 - 'A';
+                break;
+
+            case 'L':
+                if (p[1] == 'i')
+                    goto Lreal;
+                goto Ldone;
+
+            case '.':
+                if (p[1] == '.')
+                    goto Ldone; // if ".."
+                if (base == 10 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80))
+                    goto Ldone; // if ".identifier" or ".unicode"
+                goto Lreal; // otherwise as part of a floating point literal
+
+            case 'p':
+            case 'P':
+            case 'i':
+            Lreal:
+                p = start;
+                return inreal(t);
+
+            case '_':
+                ++p;
+                continue;
+
+            default:
+                goto Ldone;
+        }
+
+        uinteger_t n2 = n * base;
+        if ((n2 / base != n || n2 + d < n))
+        {
+            overflow = true;
+        }
+        n = n2 + d;
+
+        // if n needs more than 64 bits
+        if (sizeof(n) > 8 &&
+            n > 0xFFFFFFFFFFFFFFFFULL)
+        {
+            overflow = true;
+        }
+    }
+
+Ldone:
+
+    if (overflow && !err)
+    {
+        error("integer overflow");
+        err = true;
+    }
+
+    enum FLAGS
+    {
+        FLAGS_none     = 0,
+        FLAGS_decimal  = 1,             // decimal
+        FLAGS_unsigned = 2,             // u or U suffix
+        FLAGS_long     = 4,             // L suffix
+    };
+
+    FLAGS flags = (base == 10) ? FLAGS_decimal : FLAGS_none;
+
+    // Parse trailing 'u', 'U', 'l' or 'L' in any combination
+    const utf8_t *psuffix = p;
+    while (1)
+    {
+        utf8_t f;
+        switch (*p)
+        {
+            case 'U':
+            case 'u':
+                f = FLAGS_unsigned;
+                goto L1;
+
+            case 'l':
+                f = FLAGS_long;
+                error("lower case integer suffix 'l' is not allowed. Please use 'L' instead");
+                goto L1;
+
+            case 'L':
+                f = FLAGS_long;
+            L1:
+                p++;
+                if ((flags & f) && !err)
+                {
+                    error("unrecognized token");
+                    err = true;
+                }
+                flags = (FLAGS) (flags | f);
+                continue;
+            default:
+                break;
+        }
+        break;
+    }
+
+    if (base == 8 && n >= 8)
+        error("octal literals 0%llo%.*s are no longer supported, use std.conv.octal!%llo%.*s instead",
+                n, p - psuffix, psuffix, n, p - psuffix, psuffix);
+
+    TOK result;
+    switch (flags)
+    {
+        case FLAGS_none:
+            /* Octal or Hexadecimal constant.
+             * First that fits: int, uint, long, ulong
+             */
+            if (n & 0x8000000000000000LL)
+                result = TOKuns64v;
+            else if (n & 0xFFFFFFFF00000000LL)
+                result = TOKint64v;
+            else if (n & 0x80000000)
+                result = TOKuns32v;
+            else
+                result = TOKint32v;
+            break;
+
+        case FLAGS_decimal:
+            /* First that fits: int, long, long long
+             */
+            if (n & 0x8000000000000000LL)
+            {
+                if (!err)
+                {
+                    error("signed integer overflow");
+                    err = true;
+                }
+                result = TOKuns64v;
+            }
+            else if (n & 0xFFFFFFFF80000000LL)
+                result = TOKint64v;
+            else
+                result = TOKint32v;
+            break;
+
+        case FLAGS_unsigned:
+        case FLAGS_decimal | FLAGS_unsigned:
+            /* First that fits: uint, ulong
+             */
+            if (n & 0xFFFFFFFF00000000LL)
+                result = TOKuns64v;
+            else
+                result = TOKuns32v;
+            break;
+
+        case FLAGS_decimal | FLAGS_long:
+            if (n & 0x8000000000000000LL)
+            {
+                if (!err)
+                {
+                    error("signed integer overflow");
+                    err = true;
+                }
+                result = TOKuns64v;
+            }
+            else
+                result = TOKint64v;
+            break;
+
+        case FLAGS_long:
+            if (n & 0x8000000000000000LL)
+                result = TOKuns64v;
+            else
+                result = TOKint64v;
+            break;
+
+        case FLAGS_unsigned | FLAGS_long:
+        case FLAGS_decimal | FLAGS_unsigned | FLAGS_long:
+            result = TOKuns64v;
+            break;
+
+        default:
+            #ifdef DEBUG
+                printf("%x\n",flags);
+            #endif
+            assert(0);
+    }
+    t->uns64value = n;
+    return result;
+}
+
+/**************************************
+ * Read in characters, converting them to real.
+ * Bugs:
+ *      Exponent overflow not detected.
+ *      Too much requested precision is not detected.
+ */
+
+TOK Lexer::inreal(Token *t)
+{
+    //printf("Lexer::inreal()\n");
+#ifdef DEBUG
+    assert(*p == '.' || isdigit(*p));
+#endif
+    bool isWellformedString = true;
+    stringbuffer.reset();
+    const utf8_t *pstart = p;
+    char hex = 0;
+    unsigned c = *p++;
+
+    // Leading '0x'
+    if (c == '0')
+    {
+        c = *p++;
+        if (c == 'x' || c == 'X')
+        {
+            hex = true;
+            c = *p++;
+        }
+    }
+
+    // Digits to left of '.'
+    while (1)
+    {
+        if (c == '.')
+        {
+            c = *p++;
+            break;
+        }
+        if (isdigit(c) || (hex && isxdigit(c)) || c == '_')
+        {
+            c = *p++;
+            continue;
+        }
+        break;
+    }
+
+    // Digits to right of '.'
+    while (1)
+    {
+        if (isdigit(c) || (hex && isxdigit(c)) || c == '_')
+        {
+            c = *p++;
+            continue;
+        }
+        break;
+    }
+
+    if (c == 'e' || c == 'E' || (hex && (c == 'p' || c == 'P')))
+    {
+        c = *p++;
+        if (c == '-' || c == '+')
+        {
+            c = *p++;
+        }
+        bool anyexp = false;
+        while (1)
+        {
+            if (isdigit(c))
+            {
+                anyexp = true;
+                c = *p++;
+                continue;
+            }
+            if (c == '_')
+            {
+                c = *p++;
+                continue;
+            }
+            if (!anyexp)
+            {
+                error("missing exponent");
+                isWellformedString = false;
+            }
+            break;
+        }
+    }
+    else if (hex)
+    {
+        error("exponent required for hex float");
+        isWellformedString = false;
+    }
+    --p;
+    while (pstart < p)
+    {
+        if (*pstart != '_')
+            stringbuffer.writeByte(*pstart);
+        ++pstart;
+    }
+
+    stringbuffer.writeByte(0);
+    const char *sbufptr = (char *)stringbuffer.data;
+    TOK result;
+    bool isOutOfRange = false;
+    t->floatvalue = (isWellformedString ? CTFloat::parse(sbufptr, &isOutOfRange) : CTFloat::zero);
+    errno = 0;
+    switch (*p)
+    {
+        case 'F':
+        case 'f':
+            if (isWellformedString && !isOutOfRange)
+                isOutOfRange = Port::isFloat32LiteralOutOfRange(sbufptr);
+            result = TOKfloat32v;
+            p++;
+            break;
+
+        default:
+            if (isWellformedString && !isOutOfRange)
+                isOutOfRange = Port::isFloat64LiteralOutOfRange(sbufptr);
+            result = TOKfloat64v;
+            break;
+
+        case 'l':
+            error("use 'L' suffix instead of 'l'");
+        case 'L':
+            result = TOKfloat80v;
+            p++;
+            break;
+    }
+    if (*p == 'i' || *p == 'I')
+    {
+        if (*p == 'I')
+            error("use 'i' suffix instead of 'I'");
+        p++;
+        switch (result)
+        {
+            case TOKfloat32v:
+                result = TOKimaginary32v;
+                break;
+            case TOKfloat64v:
+                result = TOKimaginary64v;
+                break;
+            case TOKfloat80v:
+                result = TOKimaginary80v;
+                break;
+            default: break;
+        }
+    }
+    const bool isLong = (result == TOKfloat80v || result == TOKimaginary80v);
+    if (isOutOfRange && !isLong)
+    {
+        const char *suffix = (result == TOKfloat32v || result == TOKimaginary32v) ? "f" : "";
+        error(scanloc, "number '%s%s' is not representable", (char *)stringbuffer.data, suffix);
+    }
+#ifdef DEBUG
+    switch (result)
+    {
+        case TOKfloat32v:
+        case TOKfloat64v:
+        case TOKfloat80v:
+        case TOKimaginary32v:
+        case TOKimaginary64v:
+        case TOKimaginary80v:
+            break;
+
+        default:
+            assert(0);
+    }
+#endif
+    return result;
+}
+
+/*********************************************
+ * parse:
+ *      #line linnum [filespec]
+ * also allow __LINE__ for linnum, and __FILE__ for filespec
+ */
+
+void Lexer::poundLine()
+{
+    Token tok;
+    int linnum = this->scanloc.linnum;
+    char *filespec = NULL;
+    Loc loc = this->loc();
+
+    scan(&tok);
+    if (tok.value == TOKint32v || tok.value == TOKint64v)
+    {
+        int lin = (int)(tok.uns64value - 1);
+        if (lin != tok.uns64value - 1)
+            error("line number %lld out of range", (unsigned long long)tok.uns64value);
+        else
+            linnum = lin;
+    }
+    else if (tok.value == TOKline)
+    {
+    }
+    else
+        goto Lerr;
+
+    while (1)
+    {
+        switch (*p)
+        {
+            case 0:
+            case 0x1A:
+            case '\n':
+            Lnewline:
+                this->scanloc.linnum = linnum;
+                if (filespec)
+                    this->scanloc.filename = filespec;
+                return;
+
+            case '\r':
+                p++;
+                if (*p != '\n')
+                {   p--;
+                    goto Lnewline;
+                }
+                continue;
+
+            case ' ':
+            case '\t':
+            case '\v':
+            case '\f':
+                p++;
+                continue;                       // skip white space
+
+            case '_':
+                if (memcmp(p, "__FILE__", 8) == 0)
+                {
+                    p += 8;
+                    filespec = mem.xstrdup(scanloc.filename);
+                    continue;
+                }
+                goto Lerr;
+
+            case '"':
+                if (filespec)
+                    goto Lerr;
+                stringbuffer.reset();
+                p++;
+                while (1)
+                {   unsigned c;
+
+                    c = *p;
+                    switch (c)
+                    {
+                        case '\n':
+                        case '\r':
+                        case 0:
+                        case 0x1A:
+                            goto Lerr;
+
+                        case '"':
+                            stringbuffer.writeByte(0);
+                            filespec = mem.xstrdup((char *)stringbuffer.data);
+                            p++;
+                            break;
+
+                        default:
+                            if (c & 0x80)
+                            {   unsigned u = decodeUTF();
+                                if (u == PS || u == LS)
+                                    goto Lerr;
+                            }
+                            stringbuffer.writeByte(c);
+                            p++;
+                            continue;
+                    }
+                    break;
+                }
+                continue;
+
+            default:
+                if (*p & 0x80)
+                {   unsigned u = decodeUTF();
+                    if (u == PS || u == LS)
+                        goto Lnewline;
+                }
+                goto Lerr;
+        }
+    }
+
+Lerr:
+    error(loc, "#line integer [\"filespec\"]\\n expected");
+}
+
+
+/********************************************
+ * Decode UTF character.
+ * Issue error messages for invalid sequences.
+ * Return decoded character, advance p to last character in UTF sequence.
+ */
+
+unsigned Lexer::decodeUTF()
+{
+    dchar_t u;
+    utf8_t c;
+    const utf8_t *s = p;
+    size_t len;
+    size_t idx;
+    const char *msg;
+
+    c = *s;
+    assert(c & 0x80);
+
+    // Check length of remaining string up to 6 UTF-8 characters
+    for (len = 1; len < 6 && s[len]; len++)
+        ;
+
+    idx = 0;
+    msg = utf_decodeChar(s, len, &idx, &u);
+    p += idx - 1;
+    if (msg)
+    {
+        error("%s", msg);
+    }
+    return u;
+}
+
+
+/***************************************************
+ * Parse doc comment embedded between t->ptr and p.
+ * Remove trailing blanks and tabs from lines.
+ * Replace all newlines with \n.
+ * Remove leading comment character from each line.
+ * Decide if it's a lineComment or a blockComment.
+ * Append to previous one for this token.
+ */
+
+void Lexer::getDocComment(Token *t, unsigned lineComment)
+{
+    /* ct tells us which kind of comment it is: '/', '*', or '+'
+     */
+    utf8_t ct = t->ptr[2];
+
+    /* Start of comment text skips over / * *, / + +, or / / /
+     */
+    const utf8_t *q = t->ptr + 3;      // start of comment text
+
+    const utf8_t *qend = p;
+    if (ct == '*' || ct == '+')
+        qend -= 2;
+
+    /* Scan over initial row of ****'s or ++++'s or ////'s
+     */
+    for (; q < qend; q++)
+    {
+        if (*q != ct)
+            break;
+    }
+
+    /* Remove leading spaces until start of the comment
+     */
+    int linestart = 0;
+    if (ct == '/')
+    {
+        while (q < qend && (*q == ' ' || *q == '\t'))
+            ++q;
+    }
+    else if (q < qend)
+    {
+        if (*q == '\r')
+        {
+            ++q;
+            if (q < qend && *q == '\n')
+                ++q;
+            linestart = 1;
+        }
+        else if (*q == '\n')
+        {
+            ++q;
+            linestart = 1;
+        }
+    }
+
+    /* Remove trailing row of ****'s or ++++'s
+     */
+    if (ct != '/')
+    {
+        for (; q < qend; qend--)
+        {
+            if (qend[-1] != ct)
+                break;
+        }
+    }
+
+    /* Comment is now [q .. qend].
+     * Canonicalize it into buf[].
+     */
+    OutBuffer buf;
+
+    for (; q < qend; q++)
+    {
+        utf8_t c = *q;
+
+        switch (c)
+        {
+            case '*':
+            case '+':
+                if (linestart && c == ct)
+                {   linestart = 0;
+                    /* Trim preceding whitespace up to preceding \n
+                     */
+                    while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+                        buf.offset--;
+                    continue;
+                }
+                break;
+
+            case ' ':
+            case '\t':
+                break;
+
+            case '\r':
+                if (q[1] == '\n')
+                    continue;           // skip the \r
+                goto Lnewline;
+
+            default:
+                if (c == 226)
+                {
+                    // If LS or PS
+                    if (q[1] == 128 &&
+                        (q[2] == 168 || q[2] == 169))
+                    {
+                        q += 2;
+                        goto Lnewline;
+                    }
+                }
+                linestart = 0;
+                break;
+
+            Lnewline:
+                c = '\n';               // replace all newlines with \n
+            case '\n':
+                linestart = 1;
+
+                /* Trim trailing whitespace
+                 */
+                while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+                    buf.offset--;
+
+                break;
+        }
+        buf.writeByte(c);
+    }
+
+    /* Trim trailing whitespace (if the last line does not have newline)
+     */
+    if (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+    {
+        while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+            buf.offset--;
+    }
+
+    // Always end with a newline
+    if (!buf.offset || buf.data[buf.offset - 1] != '\n')
+        buf.writeByte('\n');
+
+    buf.writeByte(0);
+
+    // It's a line comment if the start of the doc comment comes
+    // after other non-whitespace on the same line.
+    const utf8_t** dc = (lineComment && anyToken)
+                         ? &t->lineComment
+                         : &t->blockComment;
+
+    // Combine with previous doc comment, if any
+    if (*dc)
+        *dc = combineComments(*dc, (utf8_t *)buf.data);
+    else
+        *dc = (utf8_t *)buf.extractData();
+}
+
+/********************************************
+ * Combine two document comments into one,
+ * separated by a newline.
+ */
+
+const utf8_t *Lexer::combineComments(const utf8_t *c1, const utf8_t *c2)
+{
+    //printf("Lexer::combineComments('%s', '%s')\n", c1, c2);
+
+    const utf8_t *c = c2;
+
+    if (c1)
+    {
+        c = c1;
+        if (c2)
+        {
+            size_t len1 = strlen((char *)c1);
+            size_t len2 = strlen((char *)c2);
+
+            int insertNewLine = 0;
+            if (len1 && c1[len1 - 1] != '\n')
+            {
+                ++len1;
+                insertNewLine = 1;
+            }
+
+            utf8_t *p = (utf8_t *)mem.xmalloc(len1 + 1 + len2 + 1);
+            memcpy(p, c1, len1 - insertNewLine);
+            if (insertNewLine)
+                p[len1 - 1] = '\n';
+
+            p[len1] = '\n';
+
+            memcpy(p + len1 + 1, c2, len2);
+            p[len1 + 1 + len2] = 0;
+            c = p;
+        }
+    }
+    return c;
+}
diff --git a/gcc/d/dfrontend/lexer.h b/gcc/d/dfrontend/lexer.h
new file mode 100644
index 00000000000..e6caada5548
--- /dev/null
+++ b/gcc/d/dfrontend/lexer.h
@@ -0,0 +1,83 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/lexer.h
+ */
+
+#ifndef DMD_LEXER_H
+#define DMD_LEXER_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "mars.h"
+#include "tokens.h"
+
+struct StringTable;
+class Identifier;
+
+class Lexer
+{
+public:
+    static OutBuffer stringbuffer;
+
+    Loc scanloc;                // for error messages
+
+    const utf8_t *base;        // pointer to start of buffer
+    const utf8_t *end;         // past end of buffer
+    const utf8_t *p;           // current character
+    const utf8_t *line;        // start of current line
+    Token token;
+    bool doDocComment;          // collect doc comment information
+    bool anyToken;              // !=0 means seen at least one token
+    bool commentToken;          // !=0 means comments are TOKcomment's
+    bool errors;                // errors occurred during lexing or parsing
+
+    Lexer(const char *filename,
+        const utf8_t *base, size_t begoffset, size_t endoffset,
+        bool doDocComment, bool commentToken);
+
+    TOK nextToken();
+    TOK peekNext();
+    TOK peekNext2();
+    void scan(Token *t);
+    Token *peek(Token *t);
+    Token *peekPastParen(Token *t);
+    unsigned escapeSequence();
+    TOK wysiwygStringConstant(Token *t, int tc);
+    TOK hexStringConstant(Token *t);
+    TOK delimitedStringConstant(Token *t);
+    TOK tokenStringConstant(Token *t);
+    TOK escapeStringConstant(Token *t, int wide);
+    TOK charConstant(Token *t, int wide);
+    void stringPostfix(Token *t);
+    TOK number(Token *t);
+    TOK inreal(Token *t);
+
+    Loc loc()
+    {
+        scanloc.charnum = (unsigned)(1 + p-line);
+        return scanloc;
+    }
+
+    void error(const char *format, ...);
+    void error(Loc loc, const char *format, ...);
+    void deprecation(const char *format, ...);
+    void poundLine();
+    unsigned decodeUTF();
+    void getDocComment(Token *t, unsigned lineComment);
+
+    static const utf8_t *combineComments(const utf8_t *c1, const utf8_t *c2);
+
+private:
+    void endOfLine();
+};
+
+#endif /* DMD_LEXER_H */
diff --git a/gcc/d/dfrontend/macro.h b/gcc/d/dfrontend/macro.h
new file mode 100644
index 00000000000..aee1ea2248d
--- /dev/null
+++ b/gcc/d/dfrontend/macro.h
@@ -0,0 +1,46 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/macro.h
+ */
+
+#ifndef DMD_MACRO_H
+#define DMD_MACRO_H 1
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "root.h"
+
+
+struct Macro
+{
+  private:
+    Macro *next;                // next in list
+
+    const utf8_t *name;        // macro name
+    size_t namelen;             // length of macro name
+
+    const utf8_t *text;        // macro replacement text
+    size_t textlen;             // length of replacement text
+
+    int inuse;                  // macro is in use (don't expand)
+
+    Macro(const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen);
+    Macro *search(const utf8_t *name, size_t namelen);
+
+  public:
+    static Macro *define(Macro **ptable, const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen);
+
+    void expand(OutBuffer *buf, size_t start, size_t *pend,
+        const utf8_t *arg, size_t arglen);
+};
+
+#endif
diff --git a/gcc/d/dfrontend/mars.h b/gcc/d/dfrontend/mars.h
new file mode 100644
index 00000000000..9ec4ed62ea0
--- /dev/null
+++ b/gcc/d/dfrontend/mars.h
@@ -0,0 +1,103 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/mars.h
+ */
+
+#ifndef DMD_MARS_H
+#define DMD_MARS_H
+
+#ifdef __DMC__
+#pragma once
+#endif
+
+/*
+It is very important to use version control macros correctly - the
+idea is that host and target are independent. If these are done
+correctly, cross compilers can be built.
+The host compiler and host operating system are also different,
+and are predefined by the host compiler. The ones used in
+dmd are:
+
+Macros defined by the compiler, not the code:
+
+    Compiler:
+        __DMC__         Digital Mars compiler
+        _MSC_VER        Microsoft compiler
+        __GNUC__        Gnu compiler
+        __clang__       Clang compiler
+
+    Host operating system:
+        _WIN32          Microsoft NT, Windows 95, Windows 98, Win32s,
+                        Windows 2000, Win XP, Vista
+        _WIN64          Windows for AMD64
+        __linux__       Linux
+        __APPLE__       Mac OSX
+        __FreeBSD__     FreeBSD
+        __OpenBSD__     OpenBSD
+        __sun           Solaris, OpenSolaris, SunOS, OpenIndiana, etc
+
+For the target systems, there are the target operating system and
+the target object file format:
+
+    Target operating system:
+        TARGET_WINDOS   Covers 32 bit windows and 64 bit windows
+        TARGET_LINUX    Covers 32 and 64 bit linux
+        TARGET_OSX      Covers 32 and 64 bit Mac OSX
+        TARGET_FREEBSD  Covers 32 and 64 bit FreeBSD
+        TARGET_OPENBSD  Covers 32 and 64 bit OpenBSD
+        TARGET_SOLARIS  Covers 32 and 64 bit Solaris
+
+    It is expected that the compiler for each platform will be able
+    to generate 32 and 64 bit code from the same compiler binary.
+
+    There are currently no macros for byte endianness order.
+ */
+
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#ifdef __DMC__
+#ifdef DEBUG
+#undef assert
+#define assert(e) (static_cast<void>((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt())))
+#endif
+#endif
+
+void unittests();
+
+struct OutBuffer;
+
+#include "globals.h"
+
+#include "ctfloat.h"
+
+#include "complex_t.h"
+
+#include "errors.h"
+
+class Dsymbol;
+class Library;
+struct File;
+void obj_start(char *srcfile);
+void obj_end(Library *library, File *objfile);
+void obj_append(Dsymbol *s);
+void obj_write_deferred(Library *library);
+
+/// Utility functions used by both main and frontend.
+void readFile(Loc loc, File *f);
+void writeFile(Loc loc, File *f);
+void ensurePathToNameExists(Loc loc, const char *name);
+
+const char *importHint(const char *s);
+/// Little helper function for writing out deps.
+void escapePath(OutBuffer *buf, const char *fname);
+
+#endif /* DMD_MARS_H */
diff --git a/gcc/d/dfrontend/module.h b/gcc/d/dfrontend/module.h
new file mode 100644
index 00000000000..269a9b9a87a
--- /dev/null
+++ b/gcc/d/dfrontend/module.h
@@ -0,0 +1,187 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/module.h
+ */
+
+#ifndef DMD_MODULE_H
+#define DMD_MODULE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "dsymbol.h"
+
+class ClassDeclaration;
+struct ModuleDeclaration;
+struct Macro;
+struct Escape;
+class VarDeclaration;
+class Library;
+
+enum PKG
+{
+    PKGunknown, // not yet determined whether it's a package.d or not
+    PKGmodule,  // already determined that's an actual package.d
+    PKGpackage, // already determined that's an actual package
+};
+
+class Package : public ScopeDsymbol
+{
+public:
+    PKG isPkgMod;
+    unsigned tag;       // auto incremented tag, used to mask package tree in scopes
+    Module *mod;        // != NULL if isPkgMod == PKGmodule
+
+    Package(Identifier *ident);
+    const char *kind();
+
+    static DsymbolTable *resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg);
+
+    Package *isPackage() { return this; }
+
+    bool isAncestorPackageOf(const Package * const pkg) const;
+
+    void semantic(Scope *) { }
+    Dsymbol *search(Loc loc, Identifier *ident, int flags = SearchLocalsOnly);
+    void accept(Visitor *v) { v->visit(this); }
+
+    Module *isPackageMod();
+};
+
+class Module : public Package
+{
+public:
+    static Module *rootModule;
+    static DsymbolTable *modules;       // symbol table of all modules
+    static Modules amodules;            // array of all modules
+    static Dsymbols deferred;   // deferred Dsymbol's needing semantic() run on them
+    static Dsymbols deferred2;  // deferred Dsymbol's needing semantic2() run on them
+    static Dsymbols deferred3;  // deferred Dsymbol's needing semantic3() run on them
+    static unsigned dprogress;  // progress resolving the deferred list
+    static void _init();
+
+    static AggregateDeclaration *moduleinfo;
+
+
+    const char *arg;    // original argument name
+    ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration
+    File *srcfile;      // input source file
+    const char* srcfilePath; // the path prefix to the srcfile if it applies
+    File *objfile;      // output .obj file
+    File *hdrfile;      // 'header' file
+    File *docfile;      // output documentation file
+    unsigned errors;    // if any errors in file
+    unsigned numlines;  // number of lines in source file
+    int isDocFile;      // if it is a documentation input file, not D source
+    bool isPackageFile; // if it is a package.d
+    int needmoduleinfo;
+
+    int selfimports;            // 0: don't know, 1: does not, 2: does
+    bool selfImports();         // returns true if module imports itself
+
+    int rootimports;            // 0: don't know, 1: does not, 2: does
+    bool rootImports();         // returns true if module imports root module
+
+    int insearch;
+    Identifier *searchCacheIdent;
+    Dsymbol *searchCacheSymbol; // cached value of search
+    int searchCacheFlags;       // cached flags
+
+    // module from command line we're imported from,
+    // i.e. a module that will be taken all the
+    // way to an object file
+    Module *importedFrom;
+
+    Dsymbols *decldefs;         // top level declarations for this Module
+
+    Modules aimports;             // all imported modules
+
+    unsigned debuglevel;        // debug level
+    Strings *debugids;      // debug identifiers
+    Strings *debugidsNot;       // forward referenced debug identifiers
+
+    unsigned versionlevel;      // version level
+    Strings *versionids;    // version identifiers
+    Strings *versionidsNot;     // forward referenced version identifiers
+
+    Macro *macrotable;          // document comment macros
+    Escape *escapetable;        // document comment escapes
+
+    size_t nameoffset;          // offset of module name from start of ModuleInfo
+    size_t namelen;             // length of module name in characters
+
+    Module(const char *arg, Identifier *ident, int doDocComment, int doHdrGen);
+    static Module* create(const char *arg, Identifier *ident, int doDocComment, int doHdrGen);
+
+    static Module *load(Loc loc, Identifiers *packages, Identifier *ident);
+
+    const char *kind();
+    File *setOutfile(const char *name, const char *dir, const char *arg, const char *ext);
+    void setDocfile();
+    bool read(Loc loc); // read file, returns 'true' if succeed, 'false' otherwise.
+    Module *parse();    // syntactic parse
+    void importAll(Scope *sc);
+    void semantic(Scope *);    // semantic analysis
+    void semantic2(Scope *);   // pass 2 semantic analysis
+    void semantic3(Scope *);   // pass 3 semantic analysis
+    int needModuleInfo();
+    Dsymbol *search(Loc loc, Identifier *ident, int flags = SearchLocalsOnly);
+    bool isPackageAccessible(Package *p, Prot protection, int flags = 0);
+    Dsymbol *symtabInsert(Dsymbol *s);
+    void deleteObjFile();
+    static void addDeferredSemantic(Dsymbol *s);
+    static void addDeferredSemantic2(Dsymbol *s);
+    static void addDeferredSemantic3(Dsymbol *s);
+    static void runDeferredSemantic();
+    static void runDeferredSemantic2();
+    static void runDeferredSemantic3();
+    static void clearCache();
+    int imports(Module *m);
+
+    bool isRoot() { return this->importedFrom == this; }
+    // true if the module source file is directly
+    // listed in command line.
+    bool isCoreModule(Identifier *ident);
+
+    // Back end
+
+    int doppelganger;           // sub-module
+    Symbol *cov;                // private uint[] __coverage;
+    unsigned *covb;             // bit array of valid code line numbers
+
+    Symbol *sictor;             // module order independent constructor
+    Symbol *sctor;              // module constructor
+    Symbol *sdtor;              // module destructor
+    Symbol *ssharedctor;        // module shared constructor
+    Symbol *sshareddtor;        // module shared destructor
+    Symbol *stest;              // module unit test
+
+    Symbol *sfilename;          // symbol for filename
+
+    Module *isModule() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+
+struct ModuleDeclaration
+{
+    Loc loc;
+    Identifier *id;
+    Identifiers *packages;            // array of Identifier's representing packages
+    bool isdeprecated;  // if it is a deprecated module
+    Expression *msg;
+
+    ModuleDeclaration(Loc loc, Identifiers *packages, Identifier *id);
+
+    const char *toChars();
+};
+
+#endif /* DMD_MODULE_H */
diff --git a/gcc/d/dfrontend/mtype.c b/gcc/d/dfrontend/mtype.c
new file mode 100644
index 00000000000..7a29d10598d
--- /dev/null
+++ b/gcc/d/dfrontend/mtype.c
@@ -0,0 +1,9517 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/mtype.c
+ */
+
+#define __C99FEATURES__ 1       // Needed on Solaris for NaN and more
+#define __USE_ISOC99 1          // so signbit() gets defined
+
+#include <math.h>
+#include <stdio.h>
+#include <assert.h>
+#include <float.h>
+
+#if _MSC_VER
+#include <malloc.h>
+#include <limits>
+#elif __MINGW32__
+#include <malloc.h>
+#endif
+
+#include "checkedint.h"
+#include "rmem.h"
+
+#include "dsymbol.h"
+#include "mtype.h"
+#include "scope.h"
+#include "init.h"
+#include "expression.h"
+#include "statement.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "template.h"
+#include "id.h"
+#include "enum.h"
+#include "module.h"
+#include "import.h"
+#include "aggregate.h"
+#include "hdrgen.h"
+#include "target.h"
+
+#define LOGDOTEXP       0       // log ::dotExp()
+#define LOGDEFAULTINIT  0       // log ::defaultInit()
+
+bool symbolIsVisible(Scope *sc, Dsymbol *s);
+typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param);
+int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL);
+FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
+Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
+Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
+Expression *typeToExpression(Type *t);
+Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
+Expression *initializerToExpression(Initializer *i, Type *t = NULL);
+Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
+
+int Tsize_t = Tuns32;
+int Tptrdiff_t = Tint32;
+
+/***************************** Type *****************************/
+
+ClassDeclaration *Type::dtypeinfo;
+ClassDeclaration *Type::typeinfoclass;
+ClassDeclaration *Type::typeinfointerface;
+ClassDeclaration *Type::typeinfostruct;
+ClassDeclaration *Type::typeinfopointer;
+ClassDeclaration *Type::typeinfoarray;
+ClassDeclaration *Type::typeinfostaticarray;
+ClassDeclaration *Type::typeinfoassociativearray;
+ClassDeclaration *Type::typeinfovector;
+ClassDeclaration *Type::typeinfoenum;
+ClassDeclaration *Type::typeinfofunction;
+ClassDeclaration *Type::typeinfodelegate;
+ClassDeclaration *Type::typeinfotypelist;
+ClassDeclaration *Type::typeinfoconst;
+ClassDeclaration *Type::typeinfoinvariant;
+ClassDeclaration *Type::typeinfoshared;
+ClassDeclaration *Type::typeinfowild;
+
+TemplateDeclaration *Type::rtinfo;
+
+Type *Type::tvoid;
+Type *Type::tint8;
+Type *Type::tuns8;
+Type *Type::tint16;
+Type *Type::tuns16;
+Type *Type::tint32;
+Type *Type::tuns32;
+Type *Type::tint64;
+Type *Type::tuns64;
+Type *Type::tint128;
+Type *Type::tuns128;
+Type *Type::tfloat32;
+Type *Type::tfloat64;
+Type *Type::tfloat80;
+
+Type *Type::timaginary32;
+Type *Type::timaginary64;
+Type *Type::timaginary80;
+
+Type *Type::tcomplex32;
+Type *Type::tcomplex64;
+Type *Type::tcomplex80;
+
+Type *Type::tbool;
+Type *Type::tchar;
+Type *Type::twchar;
+Type *Type::tdchar;
+
+Type *Type::tshiftcnt;
+Type *Type::terror;
+Type *Type::tnull;
+
+Type *Type::tsize_t;
+Type *Type::tptrdiff_t;
+Type *Type::thash_t;
+
+Type *Type::tvoidptr;
+Type *Type::tstring;
+Type *Type::twstring;
+Type *Type::tdstring;
+Type *Type::tvalist;
+Type *Type::basic[TMAX];
+unsigned char Type::sizeTy[TMAX];
+StringTable Type::stringtable;
+
+void initTypeMangle();
+void mangleToBuffer(Type *t, OutBuffer *buf);
+
+Type::Type(TY ty)
+{
+    this->ty = ty;
+    this->mod = 0;
+    this->deco = NULL;
+    this->cto = NULL;
+    this->ito = NULL;
+    this->sto = NULL;
+    this->scto = NULL;
+    this->wto = NULL;
+    this->wcto = NULL;
+    this->swto = NULL;
+    this->swcto = NULL;
+    this->pto = NULL;
+    this->rto = NULL;
+    this->arrayof = NULL;
+    this->vtinfo = NULL;
+    this->ctype = NULL;
+}
+
+const char *Type::kind()
+{
+    assert(false); // should be overridden
+    return NULL;
+}
+
+Type *Type::copy()
+{
+    Type *t = (Type *)mem.xmalloc(sizeTy[ty]);
+    memcpy((void*)t, (void*)this, sizeTy[ty]);
+    return t;
+}
+
+Type *Type::syntaxCopy()
+{
+    print();
+    fprintf(stderr, "ty = %d\n", ty);
+    assert(0);
+    return this;
+}
+
+bool Type::equals(RootObject *o)
+{
+    Type *t = (Type *)o;
+    //printf("Type::equals(%s, %s)\n", toChars(), t->toChars());
+    // deco strings are unique
+    // and semantic() has been run
+    if (this == o || ((t && deco == t->deco) && deco != NULL))
+    {
+        //printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
+        return true;
+    }
+    //if (deco && t && t->deco) printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
+    return false;
+}
+
+bool Type::equivalent(Type *t)
+{
+    return immutableOf()->equals(t->immutableOf());
+}
+
+void Type::_init()
+{
+    stringtable._init(14000);
+
+    for (size_t i = 0; i < TMAX; i++)
+        sizeTy[i] = sizeof(TypeBasic);
+    sizeTy[Tsarray] = sizeof(TypeSArray);
+    sizeTy[Tarray] = sizeof(TypeDArray);
+    sizeTy[Taarray] = sizeof(TypeAArray);
+    sizeTy[Tpointer] = sizeof(TypePointer);
+    sizeTy[Treference] = sizeof(TypeReference);
+    sizeTy[Tfunction] = sizeof(TypeFunction);
+    sizeTy[Tdelegate] = sizeof(TypeDelegate);
+    sizeTy[Tident] = sizeof(TypeIdentifier);
+    sizeTy[Tinstance] = sizeof(TypeInstance);
+    sizeTy[Ttypeof] = sizeof(TypeTypeof);
+    sizeTy[Tenum] = sizeof(TypeEnum);
+    sizeTy[Tstruct] = sizeof(TypeStruct);
+    sizeTy[Tclass] = sizeof(TypeClass);
+    sizeTy[Ttuple] = sizeof(TypeTuple);
+    sizeTy[Tslice] = sizeof(TypeSlice);
+    sizeTy[Treturn] = sizeof(TypeReturn);
+    sizeTy[Terror] = sizeof(TypeError);
+    sizeTy[Tnull] = sizeof(TypeNull);
+    sizeTy[Tvector] = sizeof(TypeVector);
+
+    initTypeMangle();
+
+    // Set basic types
+    static TY basetab[] =
+        { Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64,
+          Tint128, Tuns128,
+          Tfloat32, Tfloat64, Tfloat80,
+          Timaginary32, Timaginary64, Timaginary80,
+          Tcomplex32, Tcomplex64, Tcomplex80,
+          Tbool,
+          Tchar, Twchar, Tdchar, Terror };
+
+    for (size_t i = 0; basetab[i] != Terror; i++)
+    {
+        Type *t = new TypeBasic(basetab[i]);
+        t = t->merge();
+        basic[basetab[i]] = t;
+    }
+    basic[Terror] = new TypeError();
+
+    tvoid = basic[Tvoid];
+    tint8 = basic[Tint8];
+    tuns8 = basic[Tuns8];
+    tint16 = basic[Tint16];
+    tuns16 = basic[Tuns16];
+    tint32 = basic[Tint32];
+    tuns32 = basic[Tuns32];
+    tint64 = basic[Tint64];
+    tuns64 = basic[Tuns64];
+    tint128 = basic[Tint128];
+    tuns128 = basic[Tuns128];
+    tfloat32 = basic[Tfloat32];
+    tfloat64 = basic[Tfloat64];
+    tfloat80 = basic[Tfloat80];
+
+    timaginary32 = basic[Timaginary32];
+    timaginary64 = basic[Timaginary64];
+    timaginary80 = basic[Timaginary80];
+
+    tcomplex32 = basic[Tcomplex32];
+    tcomplex64 = basic[Tcomplex64];
+    tcomplex80 = basic[Tcomplex80];
+
+    tbool = basic[Tbool];
+    tchar = basic[Tchar];
+    twchar = basic[Twchar];
+    tdchar = basic[Tdchar];
+
+    tshiftcnt = tint32;
+    terror = basic[Terror];
+    tnull = basic[Tnull];
+    tnull = new TypeNull();
+    tnull->deco = tnull->merge()->deco;
+
+    tvoidptr = tvoid->pointerTo();
+    tstring = tchar->immutableOf()->arrayOf();
+    twstring = twchar->immutableOf()->arrayOf();
+    tdstring = tdchar->immutableOf()->arrayOf();
+    tvalist = Target::va_listType();
+
+    if (global.params.isLP64)
+    {
+        Tsize_t = Tuns64;
+        Tptrdiff_t = Tint64;
+    }
+    else
+    {
+        Tsize_t = Tuns32;
+        Tptrdiff_t = Tint32;
+    }
+
+    tsize_t = basic[Tsize_t];
+    tptrdiff_t = basic[Tptrdiff_t];
+    thash_t = tsize_t;
+}
+
+d_uns64 Type::size()
+{
+    return size(Loc());
+}
+
+d_uns64 Type::size(Loc loc)
+{
+    error(loc, "no size for type %s", toChars());
+    return SIZE_INVALID;
+}
+
+unsigned Type::alignsize()
+{
+    return (unsigned)size(Loc());
+}
+
+Type *Type::semantic(Loc loc, Scope *sc)
+{
+    if (ty == Tint128 || ty == Tuns128)
+    {
+        error(loc, "cent and ucent types not implemented");
+        return terror;
+    }
+
+    return merge();
+}
+
+Type *Type::trySemantic(Loc loc, Scope *sc)
+{
+    //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
+    unsigned errors = global.startGagging();
+    Type *t = semantic(loc, sc);
+    if (global.endGagging(errors) || t->ty == Terror)        // if any errors happened
+    {
+        t = NULL;
+    }
+    //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
+    return t;
+}
+
+/********************************
+ * Return a copy of this type with all attributes null-initialized.
+ * Useful for creating a type with different modifiers.
+ */
+
+Type *Type::nullAttributes()
+{
+    unsigned sz = sizeTy[ty];
+    Type *t = (Type *)mem.xmalloc(sz);
+    memcpy((void*)t, (void*)this, sz);
+    // t->mod = NULL;  // leave mod unchanged
+    t->deco = NULL;
+    t->arrayof = NULL;
+    t->pto = NULL;
+    t->rto = NULL;
+    t->cto = NULL;
+    t->ito = NULL;
+    t->sto = NULL;
+    t->scto = NULL;
+    t->wto = NULL;
+    t->wcto = NULL;
+    t->swto = NULL;
+    t->swcto = NULL;
+    t->vtinfo = NULL;
+    t->ctype = NULL;
+    if (t->ty == Tstruct) ((TypeStruct *)t)->att = RECfwdref;
+    if (t->ty == Tclass) ((TypeClass *)t)->att = RECfwdref;
+    return t;
+}
+
+/********************************
+ * Convert to 'const'.
+ */
+
+Type *Type::constOf()
+{
+    //printf("Type::constOf() %p %s\n", this, toChars());
+    if (mod == MODconst)
+        return this;
+    if (cto)
+    {
+        assert(cto->mod == MODconst);
+        return cto;
+    }
+    Type *t = makeConst();
+    t = t->merge();
+    t->fixTo(this);
+    //printf("-Type::constOf() %p %s\n", t, t->toChars());
+    return t;
+}
+
+/********************************
+ * Convert to 'immutable'.
+ */
+
+Type *Type::immutableOf()
+{
+    //printf("Type::immutableOf() %p %s\n", this, toChars());
+    if (isImmutable())
+        return this;
+    if (ito)
+    {
+        assert(ito->isImmutable());
+        return ito;
+    }
+    Type *t = makeImmutable();
+    t = t->merge();
+    t->fixTo(this);
+    //printf("\t%p\n", t);
+    return t;
+}
+
+/********************************
+ * Make type mutable.
+ */
+
+Type *Type::mutableOf()
+{
+    //printf("Type::mutableOf() %p, %s\n", this, toChars());
+    Type *t = this;
+    if (isImmutable())
+    {
+        t = ito;                // immutable => naked
+        assert(!t || (t->isMutable() && !t->isShared()));
+    }
+    else if (isConst())
+    {
+        if (isShared())
+        {
+            if (isWild())
+                t = swcto;      // shared wild const -> shared
+            else
+                t = sto;        // shared const => shared
+        }
+        else
+        {
+            if (isWild())
+                t = wcto;       // wild const -> naked
+            else
+                t = cto;        // const => naked
+        }
+        assert(!t || t->isMutable());
+    }
+    else if (isWild())
+    {
+        if (isShared())
+            t = sto;            // shared wild => shared
+        else
+            t = wto;            // wild => naked
+        assert(!t || t->isMutable());
+    }
+    if (!t)
+    {
+        t = makeMutable();
+        t = t->merge();
+        t->fixTo(this);
+    }
+    else
+        t = t->merge();
+    assert(t->isMutable());
+    return t;
+}
+
+Type *Type::sharedOf()
+{
+    //printf("Type::sharedOf() %p, %s\n", this, toChars());
+    if (mod == MODshared)
+        return this;
+    if (sto)
+    {
+        assert(sto->mod == MODshared);
+        return sto;
+    }
+    Type *t = makeShared();
+    t = t->merge();
+    t->fixTo(this);
+    //printf("\t%p\n", t);
+    return t;
+}
+
+Type *Type::sharedConstOf()
+{
+    //printf("Type::sharedConstOf() %p, %s\n", this, toChars());
+    if (mod == (MODshared | MODconst))
+        return this;
+    if (scto)
+    {
+        assert(scto->mod == (MODshared | MODconst));
+        return scto;
+    }
+    Type *t = makeSharedConst();
+    t = t->merge();
+    t->fixTo(this);
+    //printf("\t%p\n", t);
+    return t;
+}
+
+
+/********************************
+ * Make type unshared.
+ *      0            => 0
+ *      const        => const
+ *      immutable    => immutable
+ *      shared       => 0
+ *      shared const => const
+ *      wild         => wild
+ *      wild const   => wild const
+ *      shared wild  => wild
+ *      shared wild const => wild const
+ */
+
+Type *Type::unSharedOf()
+{
+    //printf("Type::unSharedOf() %p, %s\n", this, toChars());
+    Type *t = this;
+
+    if (isShared())
+    {
+        if (isWild())
+        {
+            if (isConst())
+                t = wcto;   // shared wild const => wild const
+            else
+                t = wto;    // shared wild => wild
+        }
+        else
+        {
+            if (isConst())
+                t = cto;    // shared const => const
+            else
+                t = sto;    // shared => naked
+        }
+        assert(!t || !t->isShared());
+    }
+
+    if (!t)
+    {
+        t = this->nullAttributes();
+        t->mod = mod & ~MODshared;
+        t->ctype = ctype;
+        t = t->merge();
+
+        t->fixTo(this);
+    }
+    else
+        t = t->merge();
+    assert(!t->isShared());
+    return t;
+}
+
+/********************************
+ * Convert to 'wild'.
+ */
+
+Type *Type::wildOf()
+{
+    //printf("Type::wildOf() %p %s\n", this, toChars());
+    if (mod == MODwild)
+        return this;
+    if (wto)
+    {
+        assert(wto->mod == MODwild);
+        return wto;
+    }
+    Type *t = makeWild();
+    t = t->merge();
+    t->fixTo(this);
+    //printf("\t%p %s\n", t, t->toChars());
+    return t;
+}
+
+Type *Type::wildConstOf()
+{
+    //printf("Type::wildConstOf() %p %s\n", this, toChars());
+    if (mod == MODwildconst)
+        return this;
+    if (wcto)
+    {
+        assert(wcto->mod == MODwildconst);
+        return wcto;
+    }
+    Type *t = makeWildConst();
+    t = t->merge();
+    t->fixTo(this);
+    //printf("\t%p %s\n", t, t->toChars());
+    return t;
+}
+
+Type *Type::sharedWildOf()
+{
+    //printf("Type::sharedWildOf() %p, %s\n", this, toChars());
+    if (mod == (MODshared | MODwild))
+        return this;
+    if (swto)
+    {
+        assert(swto->mod == (MODshared | MODwild));
+        return swto;
+    }
+    Type *t = makeSharedWild();
+    t = t->merge();
+    t->fixTo(this);
+    //printf("\t%p %s\n", t, t->toChars());
+    return t;
+}
+
+Type *Type::sharedWildConstOf()
+{
+    //printf("Type::sharedWildConstOf() %p, %s\n", this, toChars());
+    if (mod == (MODshared | MODwildconst))
+        return this;
+    if (swcto)
+    {
+        assert(swcto->mod == (MODshared | MODwildconst));
+        return swcto;
+    }
+    Type *t = makeSharedWildConst();
+    t = t->merge();
+    t->fixTo(this);
+    //printf("\t%p %s\n", t, t->toChars());
+    return t;
+}
+
+/**********************************
+ * For our new type 'this', which is type-constructed from t,
+ * fill in the cto, ito, sto, scto, wto shortcuts.
+ */
+
+void Type::fixTo(Type *t)
+{
+    // If fixing this: immutable(T*) by t: immutable(T)*,
+    // cache t to this->xto won't break transitivity.
+    Type *mto = NULL;
+    Type *tn = nextOf();
+    if (!tn || ty != Tsarray && tn->mod == t->nextOf()->mod)
+    {
+        switch (t->mod)
+        {
+            case 0:                           mto = t;  break;
+            case MODconst:                    cto = t;  break;
+            case MODwild:                     wto = t;  break;
+            case MODwildconst:               wcto = t;  break;
+            case MODshared:                   sto = t;  break;
+            case MODshared | MODconst:       scto = t;  break;
+            case MODshared | MODwild:        swto = t;  break;
+            case MODshared | MODwildconst:  swcto = t;  break;
+            case MODimmutable:                ito = t;  break;
+        }
+    }
+
+    assert(mod != t->mod);
+#define X(m, n) (((m) << 4) | (n))
+    switch (mod)
+    {
+        case 0:
+            break;
+
+        case MODconst:
+            cto = mto;
+            t->cto = this;
+            break;
+
+        case MODwild:
+            wto = mto;
+            t->wto = this;
+            break;
+
+        case MODwildconst:
+            wcto = mto;
+            t->wcto = this;
+            break;
+
+        case MODshared:
+            sto = mto;
+            t->sto = this;
+            break;
+
+        case MODshared | MODconst:
+            scto = mto;
+            t->scto = this;
+            break;
+
+        case MODshared | MODwild:
+            swto = mto;
+            t->swto = this;
+            break;
+
+        case MODshared | MODwildconst:
+            swcto = mto;
+            t->swcto = this;
+            break;
+
+        case MODimmutable:
+            t->ito = this;
+            if (t->  cto) t->  cto->ito = this;
+            if (t->  sto) t->  sto->ito = this;
+            if (t-> scto) t-> scto->ito = this;
+            if (t->  wto) t->  wto->ito = this;
+            if (t-> wcto) t-> wcto->ito = this;
+            if (t-> swto) t-> swto->ito = this;
+            if (t->swcto) t->swcto->ito = this;
+            break;
+
+        default:
+            assert(0);
+    }
+#undef X
+
+    check();
+    t->check();
+    //printf("fixTo: %s, %s\n", toChars(), t->toChars());
+}
+
+/***************************
+ * Look for bugs in constructing types.
+ */
+
+void Type::check()
+{
+    switch (mod)
+    {
+        case 0:
+            if (cto) assert(cto->mod == MODconst);
+            if (ito) assert(ito->mod == MODimmutable);
+            if (sto) assert(sto->mod == MODshared);
+            if (scto) assert(scto->mod == (MODshared | MODconst));
+            if (wto) assert(wto->mod == MODwild);
+            if (wcto) assert(wcto->mod == MODwildconst);
+            if (swto) assert(swto->mod == (MODshared | MODwild));
+            if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+            break;
+
+        case MODconst:
+            if (cto) assert(cto->mod == 0);
+            if (ito) assert(ito->mod == MODimmutable);
+            if (sto) assert(sto->mod == MODshared);
+            if (scto) assert(scto->mod == (MODshared | MODconst));
+            if (wto) assert(wto->mod == MODwild);
+            if (wcto) assert(wcto->mod == MODwildconst);
+            if (swto) assert(swto->mod == (MODshared | MODwild));
+            if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+            break;
+
+        case MODwild:
+            if (cto) assert(cto->mod == MODconst);
+            if (ito) assert(ito->mod == MODimmutable);
+            if (sto) assert(sto->mod == MODshared);
+            if (scto) assert(scto->mod == (MODshared | MODconst));
+            if (wto) assert(wto->mod == 0);
+            if (wcto) assert(wcto->mod == MODwildconst);
+            if (swto) assert(swto->mod == (MODshared | MODwild));
+            if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+            break;
+
+        case MODwildconst:
+            assert(!  cto ||   cto->mod == MODconst);
+            assert(!  ito ||   ito->mod == MODimmutable);
+            assert(!  sto ||   sto->mod == MODshared);
+            assert(! scto ||  scto->mod == (MODshared | MODconst));
+            assert(!  wto ||   wto->mod == MODwild);
+            assert(! wcto ||  wcto->mod == 0);
+            assert(! swto ||  swto->mod == (MODshared | MODwild));
+            assert(!swcto || swcto->mod == (MODshared | MODwildconst));
+            break;
+
+        case MODshared:
+            if (cto) assert(cto->mod == MODconst);
+            if (ito) assert(ito->mod == MODimmutable);
+            if (sto) assert(sto->mod == 0);
+            if (scto) assert(scto->mod == (MODshared | MODconst));
+            if (wto) assert(wto->mod == MODwild);
+            if (wcto) assert(wcto->mod == MODwildconst);
+            if (swto) assert(swto->mod == (MODshared | MODwild));
+            if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+            break;
+
+        case MODshared | MODconst:
+            if (cto) assert(cto->mod == MODconst);
+            if (ito) assert(ito->mod == MODimmutable);
+            if (sto) assert(sto->mod == MODshared);
+            if (scto) assert(scto->mod == 0);
+            if (wto) assert(wto->mod == MODwild);
+            if (wcto) assert(wcto->mod == MODwildconst);
+            if (swto) assert(swto->mod == (MODshared | MODwild));
+            if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+            break;
+
+        case MODshared | MODwild:
+            if (cto) assert(cto->mod == MODconst);
+            if (ito) assert(ito->mod == MODimmutable);
+            if (sto) assert(sto->mod == MODshared);
+            if (scto) assert(scto->mod == (MODshared | MODconst));
+            if (wto) assert(wto->mod == MODwild);
+            if (wcto) assert(wcto->mod == MODwildconst);
+            if (swto) assert(swto->mod == 0);
+            if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+            break;
+
+        case MODshared | MODwildconst:
+            assert(!  cto ||   cto->mod == MODconst);
+            assert(!  ito ||   ito->mod == MODimmutable);
+            assert(!  sto ||   sto->mod == MODshared);
+            assert(! scto ||  scto->mod == (MODshared | MODconst));
+            assert(!  wto ||   wto->mod == MODwild);
+            assert(! wcto ||  wcto->mod == MODwildconst);
+            assert(! swto ||  swto->mod == (MODshared | MODwild));
+            assert(!swcto || swcto->mod == 0);
+            break;
+
+        case MODimmutable:
+            if (cto) assert(cto->mod == MODconst);
+            if (ito) assert(ito->mod == 0);
+            if (sto) assert(sto->mod == MODshared);
+            if (scto) assert(scto->mod == (MODshared | MODconst));
+            if (wto) assert(wto->mod == MODwild);
+            if (wcto) assert(wcto->mod == MODwildconst);
+            if (swto) assert(swto->mod == (MODshared | MODwild));
+            if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+            break;
+
+        default:
+            assert(0);
+    }
+
+    Type *tn = nextOf();
+    if (tn && ty != Tfunction && tn->ty != Tfunction && ty != Tenum)
+    {
+        // Verify transitivity
+        switch (mod)
+        {
+            case 0:
+            case MODconst:
+            case MODwild:
+            case MODwildconst:
+            case MODshared:
+            case MODshared | MODconst:
+            case MODshared | MODwild:
+            case MODshared | MODwildconst:
+            case MODimmutable:
+                assert(tn->mod == MODimmutable || (tn->mod & mod) == mod);
+                break;
+
+            default:
+                assert(0);
+        }
+        tn->check();
+    }
+}
+
+Type *Type::makeConst()
+{
+    //printf("Type::makeConst() %p, %s\n", this, toChars());
+    if (cto) return cto;
+    Type *t = this->nullAttributes();
+    t->mod = MODconst;
+    //printf("-Type::makeConst() %p, %s\n", t, toChars());
+    return t;
+}
+
+Type *Type::makeImmutable()
+{
+    if (ito) return ito;
+    Type *t = this->nullAttributes();
+    t->mod = MODimmutable;
+    return t;
+}
+
+Type *Type::makeShared()
+{
+    if (sto) return sto;
+    Type *t = this->nullAttributes();
+    t->mod = MODshared;
+    return t;
+}
+
+Type *Type::makeSharedConst()
+{
+    if (scto) return scto;
+    Type *t = this->nullAttributes();
+    t->mod = MODshared | MODconst;
+    return t;
+}
+
+Type *Type::makeWild()
+{
+    if (wto) return wto;
+    Type *t = this->nullAttributes();
+    t->mod = MODwild;
+    return t;
+}
+
+Type *Type::makeWildConst()
+{
+    if (wcto) return wcto;
+    Type *t = this->nullAttributes();
+    t->mod = MODwildconst;
+    return t;
+}
+
+Type *Type::makeSharedWild()
+{
+    if (swto) return swto;
+    Type *t = this->nullAttributes();
+    t->mod = MODshared | MODwild;
+    return t;
+}
+
+Type *Type::makeSharedWildConst()
+{
+    if (swcto) return swcto;
+    Type *t = this->nullAttributes();
+    t->mod = MODshared | MODwildconst;
+    return t;
+}
+
+Type *Type::makeMutable()
+{
+    Type *t = this->nullAttributes();
+    t->mod = mod & MODshared;
+    return t;
+}
+
+/*************************************
+ * Apply STCxxxx bits to existing type.
+ * Use *before* semantic analysis is run.
+ */
+
+Type *Type::addSTC(StorageClass stc)
+{
+    Type *t = this;
+    if (t->isImmutable())
+        ;
+    else if (stc & STCimmutable)
+    {
+        t = t->makeImmutable();
+    }
+    else
+    {
+        if ((stc & STCshared) && !t->isShared())
+        {
+            if (t->isWild())
+            {
+                if (t->isConst())
+                    t = t->makeSharedWildConst();
+                else
+                    t = t->makeSharedWild();
+            }
+            else
+            {
+                if (t->isConst())
+                    t = t->makeSharedConst();
+                else
+                    t = t->makeShared();
+            }
+        }
+        if ((stc & STCconst) && !t->isConst())
+        {
+            if (t->isShared())
+            {
+                if (t->isWild())
+                    t = t->makeSharedWildConst();
+                else
+                    t = t->makeSharedConst();
+            }
+            else
+            {
+                if (t->isWild())
+                    t = t->makeWildConst();
+                else
+                    t = t->makeConst();
+            }
+        }
+        if ((stc & STCwild) && !t->isWild())
+        {
+            if (t->isShared())
+            {
+                if (t->isConst())
+                    t = t->makeSharedWildConst();
+                else
+                    t = t->makeSharedWild();
+            }
+            else
+            {
+                if (t->isConst())
+                    t = t->makeWildConst();
+                else
+                    t = t->makeWild();
+            }
+        }
+    }
+    return t;
+}
+
+/************************************
+ * Convert MODxxxx to STCxxx
+ */
+
+StorageClass ModToStc(unsigned mod)
+{
+    StorageClass stc = 0;
+    if (mod & MODimmutable) stc |= STCimmutable;
+    if (mod & MODconst)     stc |= STCconst;
+    if (mod & MODwild)      stc |= STCwild;
+    if (mod & MODshared)    stc |= STCshared;
+    return stc;
+}
+
+/************************************
+ * Apply MODxxxx bits to existing type.
+ */
+
+Type *Type::castMod(MOD mod)
+{   Type *t;
+
+    switch (mod)
+    {
+        case 0:
+            t = unSharedOf()->mutableOf();
+            break;
+
+        case MODconst:
+            t = unSharedOf()->constOf();
+            break;
+
+        case MODwild:
+            t = unSharedOf()->wildOf();
+            break;
+
+        case MODwildconst:
+            t = unSharedOf()->wildConstOf();
+            break;
+
+        case MODshared:
+            t = mutableOf()->sharedOf();
+            break;
+
+        case MODshared | MODconst:
+            t = sharedConstOf();
+            break;
+
+        case MODshared | MODwild:
+            t = sharedWildOf();
+            break;
+
+        case MODshared | MODwildconst:
+            t = sharedWildConstOf();
+            break;
+
+        case MODimmutable:
+            t = immutableOf();
+            break;
+
+        default:
+            assert(0);
+    }
+    return t;
+}
+
+/************************************
+ * Add MODxxxx bits to existing type.
+ * We're adding, not replacing, so adding const to
+ * a shared type => "shared const"
+ */
+
+Type *Type::addMod(MOD mod)
+{
+    /* Add anything to immutable, and it remains immutable
+     */
+    Type *t = this;
+    if (!t->isImmutable())
+    {
+        //printf("addMod(%x) %s\n", mod, toChars());
+        switch (mod)
+        {
+            case 0:
+                break;
+
+            case MODconst:
+                if (isShared())
+                {
+                    if (isWild())
+                        t = sharedWildConstOf();
+                    else
+                        t = sharedConstOf();
+                }
+                else
+                {
+                    if (isWild())
+                        t = wildConstOf();
+                    else
+                        t = constOf();
+                }
+                break;
+
+            case MODwild:
+                if (isShared())
+                {
+                    if (isConst())
+                        t = sharedWildConstOf();
+                    else
+                        t = sharedWildOf();
+                }
+                else
+                {
+                    if (isConst())
+                        t = wildConstOf();
+                    else
+                        t = wildOf();
+                }
+                break;
+
+            case MODwildconst:
+                if (isShared())
+                    t = sharedWildConstOf();
+                else
+                    t = wildConstOf();
+                break;
+
+            case MODshared:
+                if (isWild())
+                {
+                    if (isConst())
+                        t = sharedWildConstOf();
+                    else
+                        t = sharedWildOf();
+                }
+                else
+                {
+                    if (isConst())
+                        t = sharedConstOf();
+                    else
+                        t = sharedOf();
+                }
+                break;
+
+            case MODshared | MODconst:
+                if (isWild())
+                    t = sharedWildConstOf();
+                else
+                    t = sharedConstOf();
+                break;
+
+            case MODshared | MODwild:
+                if (isConst())
+                    t = sharedWildConstOf();
+                else
+                    t = sharedWildOf();
+                break;
+
+            case MODshared | MODwildconst:
+                t = sharedWildConstOf();
+                break;
+
+            case MODimmutable:
+                t = immutableOf();
+                break;
+
+            default:
+                assert(0);
+        }
+    }
+    return t;
+}
+
+/************************************
+ * Add storage class modifiers to type.
+ */
+
+Type *Type::addStorageClass(StorageClass stc)
+{
+    /* Just translate to MOD bits and let addMod() do the work
+     */
+    MOD mod = 0;
+
+    if (stc & STCimmutable)
+        mod = MODimmutable;
+    else
+    {
+        if (stc & (STCconst | STCin))
+            mod |= MODconst;
+        if (stc & STCwild)
+            mod |= MODwild;
+        if (stc & STCshared)
+            mod |= MODshared;
+    }
+    return addMod(mod);
+}
+
+Type *Type::pointerTo()
+{
+    if (ty == Terror)
+        return this;
+    if (!pto)
+    {
+        Type *t = new TypePointer(this);
+        if (ty == Tfunction)
+        {
+            t->deco = t->merge()->deco;
+            pto = t;
+        }
+        else
+            pto = t->merge();
+    }
+    return pto;
+}
+
+Type *Type::referenceTo()
+{
+    if (ty == Terror)
+        return this;
+    if (!rto)
+    {
+        Type *t = new TypeReference(this);
+        rto = t->merge();
+    }
+    return rto;
+}
+
+Type *Type::arrayOf()
+{
+    if (ty == Terror)
+        return this;
+    if (!arrayof)
+    {
+        Type *t = new TypeDArray(this);
+        arrayof = t->merge();
+    }
+    return arrayof;
+}
+
+// Make corresponding static array type without semantic
+Type *Type::sarrayOf(dinteger_t dim)
+{
+    assert(deco);
+    Type *t = new TypeSArray(this, new IntegerExp(Loc(), dim, Type::tsize_t));
+
+    // according to TypeSArray::semantic()
+    t = t->addMod(mod);
+    t = t->merge();
+
+    return t;
+}
+
+Type *Type::aliasthisOf()
+{
+    AggregateDeclaration *ad = isAggregate(this);
+    if (ad && ad->aliasthis)
+    {
+        Dsymbol *s = ad->aliasthis;
+        if (s->isAliasDeclaration())
+            s = s->toAlias();
+        Declaration *d = s->isDeclaration();
+        if (d && !d->isTupleDeclaration())
+        {
+            assert(d->type);
+            Type *t = d->type;
+            if (d->isVarDeclaration() && d->needThis())
+            {
+                t = t->addMod(this->mod);
+            }
+            else if (d->isFuncDeclaration())
+            {
+                FuncDeclaration *fd = resolveFuncCall(Loc(), NULL, d, NULL, this, NULL, 1);
+                if (fd && fd->errors)
+                    return Type::terror;
+                if (fd && !fd->type->nextOf() && !fd->functionSemantic())
+                    fd = NULL;
+                if (fd)
+                {
+                    t = fd->type->nextOf();
+                    if (!t) // issue 14185
+                        return Type::terror;
+                    t = t->substWildTo(mod == 0 ? MODmutable : mod);
+                }
+                else
+                    return Type::terror;
+            }
+            return t;
+        }
+        EnumDeclaration *ed = s->isEnumDeclaration();
+        if (ed)
+        {
+            Type *t = ed->type;
+            return t;
+        }
+        TemplateDeclaration *td = s->isTemplateDeclaration();
+        if (td)
+        {
+            assert(td->_scope);
+            FuncDeclaration *fd = resolveFuncCall(Loc(), NULL, td, NULL, this, NULL, 1);
+            if (fd && fd->errors)
+                return Type::terror;
+            if (fd && fd->functionSemantic())
+            {
+                Type *t = fd->type->nextOf();
+                t = t->substWildTo(mod == 0 ? MODmutable : mod);
+                return t;
+            }
+            else
+                return Type::terror;
+        }
+        //printf("%s\n", s->kind());
+    }
+    return NULL;
+}
+
+bool Type::checkAliasThisRec()
+{
+    Type *tb = toBasetype();
+    AliasThisRec* pflag;
+    if (tb->ty == Tstruct)
+        pflag = &((TypeStruct *)tb)->att;
+    else if (tb->ty == Tclass)
+        pflag = &((TypeClass *)tb)->att;
+    else
+        return false;
+
+    AliasThisRec flag = (AliasThisRec)(*pflag & RECtypeMask);
+    if (flag == RECfwdref)
+    {
+        Type *att = aliasthisOf();
+        flag = att && att->implicitConvTo(this) ? RECyes : RECno;
+    }
+    *pflag = (AliasThisRec)(flag | (*pflag & ~RECtypeMask));
+    return flag == RECyes;
+}
+
+Dsymbol *Type::toDsymbol(Scope *sc)
+{
+    return NULL;
+}
+
+/*******************************
+ * If this is a shell around another type,
+ * get that other type.
+ */
+
+Type *Type::toBasetype()
+{
+    return this;
+}
+
+/***************************
+ * Return !=0 if modfrom can be implicitly converted to modto
+ */
+bool MODimplicitConv(MOD modfrom, MOD modto)
+{
+    if (modfrom == modto)
+        return true;
+
+    //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto);
+    #define X(m, n) (((m) << 4) | (n))
+    switch (X(modfrom & ~MODshared, modto & ~MODshared))
+    {
+        case X(0,            MODconst):
+        case X(MODwild,      MODconst):
+        case X(MODwild,      MODwildconst):
+        case X(MODwildconst, MODconst):
+            return (modfrom & MODshared) == (modto & MODshared);
+
+        case X(MODimmutable, MODconst):
+        case X(MODimmutable, MODwildconst):
+            return true;
+
+        default:
+            return false;
+    }
+    #undef X
+}
+
+/***************************
+ * Return MATCHexact or MATCHconst if a method of type '() modfrom' can call a method of type '() modto'.
+ */
+MATCH MODmethodConv(MOD modfrom, MOD modto)
+{
+    if (modfrom == modto)
+        return MATCHexact;
+    if (MODimplicitConv(modfrom, modto))
+        return MATCHconst;
+
+    #define X(m, n) (((m) << 4) | (n))
+    switch (X(modfrom, modto))
+    {
+        case X(0,            MODwild):
+        case X(MODimmutable, MODwild):
+        case X(MODconst,     MODwild):
+        case X(MODwildconst, MODwild):
+        case X(MODshared,              MODshared|MODwild):
+        case X(MODshared|MODimmutable, MODshared|MODwild):
+        case X(MODshared|MODconst,     MODshared|MODwild):
+        case X(MODshared|MODwildconst, MODshared|MODwild):
+            return MATCHconst;
+
+        default:
+            return MATCHnomatch;
+    }
+    #undef X
+}
+
+/***************************
+ * Merge mod bits to form common mod.
+ */
+MOD MODmerge(MOD mod1, MOD mod2)
+{
+    if (mod1 == mod2)
+        return mod1;
+
+    //printf("MODmerge(1 = %x, 2 = %x)\n", mod1, mod2);
+    MOD result = 0;
+    if ((mod1 | mod2) & MODshared)
+    {
+        // If either type is shared, the result will be shared
+        result |= MODshared;
+        mod1 &= ~MODshared;
+        mod2 &= ~MODshared;
+    }
+    if (mod1 == 0 || mod1 == MODmutable || mod1 == MODconst ||
+        mod2 == 0 || mod2 == MODmutable || mod2 == MODconst)
+    {
+        // If either type is mutable or const, the result will be const.
+        result |= MODconst;
+    }
+    else
+    {
+        // MODimmutable vs MODwild
+        // MODimmutable vs MODwildconst
+        //      MODwild vs MODwildconst
+        assert(mod1 & MODwild || mod2 & MODwild);
+        result |= MODwildconst;
+    }
+    return result;
+}
+
+/*********************************
+ * Store modifier name into buf.
+ */
+void MODtoBuffer(OutBuffer *buf, MOD mod)
+{
+    switch (mod)
+    {
+        case 0:
+            break;
+
+        case MODimmutable:
+            buf->writestring(Token::tochars[TOKimmutable]);
+            break;
+
+        case MODshared:
+            buf->writestring(Token::tochars[TOKshared]);
+            break;
+
+        case MODshared | MODconst:
+            buf->writestring(Token::tochars[TOKshared]);
+            buf->writeByte(' ');
+            /* fall through */
+        case MODconst:
+            buf->writestring(Token::tochars[TOKconst]);
+            break;
+
+        case MODshared | MODwild:
+            buf->writestring(Token::tochars[TOKshared]);
+            buf->writeByte(' ');
+            /* fall through */
+        case MODwild:
+            buf->writestring(Token::tochars[TOKwild]);
+            break;
+
+        case MODshared | MODwildconst:
+            buf->writestring(Token::tochars[TOKshared]);
+            buf->writeByte(' ');
+            /* fall through */
+        case MODwildconst:
+            buf->writestring(Token::tochars[TOKwild]);
+            buf->writeByte(' ');
+            buf->writestring(Token::tochars[TOKconst]);
+            break;
+
+        default:
+            assert(0);
+    }
+}
+
+
+/*********************************
+ * Return modifier name.
+ */
+char *MODtoChars(MOD mod)
+{
+    OutBuffer buf;
+    buf.reserve(16);
+    MODtoBuffer(&buf, mod);
+    return buf.extractString();
+}
+
+/********************************
+ * For pretty-printing a type.
+ */
+
+const char *Type::toChars()
+{
+    OutBuffer buf;
+    buf.reserve(16);
+    HdrGenState hgs;
+    hgs.fullQual = (ty == Tclass && !mod);
+
+    ::toCBuffer(this, &buf, NULL, &hgs);
+    return buf.extractString();
+}
+
+char *Type::toPrettyChars(bool QualifyTypes)
+{
+    OutBuffer buf;
+    buf.reserve(16);
+    HdrGenState hgs;
+    hgs.fullQual = QualifyTypes;
+
+    ::toCBuffer(this, &buf, NULL, &hgs);
+    return buf.extractString();
+}
+
+/*********************************
+ * Store this type's modifier name into buf.
+ */
+void Type::modToBuffer(OutBuffer *buf)
+{
+    if (mod)
+    {
+        buf->writeByte(' ');
+        MODtoBuffer(buf, mod);
+    }
+}
+
+/*********************************
+ * Return this type's modifier name.
+ */
+char *Type::modToChars()
+{
+    OutBuffer buf;
+    buf.reserve(16);
+    modToBuffer(&buf);
+    return buf.extractString();
+}
+
+/** For each active modifier (MODconst, MODimmutable, etc) call fp with a
+void* for the work param and a string representation of the attribute. */
+int Type::modifiersApply(void *param, int (*fp)(void *, const char *))
+{
+    static unsigned char modsArr[] = { MODconst, MODimmutable, MODwild, MODshared };
+
+    for (size_t idx = 0; idx < 4; ++idx)
+    {
+        if (mod & modsArr[idx])
+        {
+            if (int res = fp(param, MODtoChars(modsArr[idx])))
+                return res;
+        }
+    }
+    return 0;
+}
+
+/************************************
+ * Strip all parameter's idenfiers and their default arguments for merging types.
+ * If some of parameter types or return type are function pointer, delegate, or
+ * the types which contains either, then strip also from them.
+ */
+
+Type *stripDefaultArgs(Type *t)
+{
+  struct N
+  {
+    static Parameters *stripParams(Parameters *parameters)
+    {
+        Parameters *params = parameters;
+        if (params && params->dim > 0)
+        {
+            for (size_t i = 0; i < params->dim; i++)
+            {
+                Parameter *p = (*params)[i];
+                Type *ta = stripDefaultArgs(p->type);
+                if (ta != p->type || p->defaultArg || p->ident)
+                {
+                    if (params == parameters)
+                    {
+                        params = new Parameters();
+                        params->setDim(parameters->dim);
+                        for (size_t j = 0; j < params->dim; j++)
+                            (*params)[j] = (*parameters)[j];
+                    }
+                    (*params)[i] = new Parameter(p->storageClass, ta, NULL, NULL);
+                }
+            }
+        }
+        return params;
+    }
+  };
+
+    if (t == NULL)
+        return t;
+
+    if (t->ty == Tfunction)
+    {
+        TypeFunction *tf = (TypeFunction *)t;
+        Type *tret = stripDefaultArgs(tf->next);
+        Parameters *params = N::stripParams(tf->parameters);
+        if (tret == tf->next && params == tf->parameters)
+            goto Lnot;
+        tf = (TypeFunction *)tf->copy();
+        tf->parameters = params;
+        tf->next = tret;
+        //printf("strip %s\n   <- %s\n", tf->toChars(), t->toChars());
+        t = tf;
+    }
+    else if (t->ty == Ttuple)
+    {
+        TypeTuple *tt = (TypeTuple *)t;
+        Parameters *args = N::stripParams(tt->arguments);
+        if (args == tt->arguments)
+            goto Lnot;
+        t = t->copy();
+        ((TypeTuple *)t)->arguments = args;
+    }
+    else if (t->ty == Tenum)
+    {
+        // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
+        goto Lnot;
+    }
+    else
+    {
+        Type *tn = t->nextOf();
+        Type *n = stripDefaultArgs(tn);
+        if (n == tn)
+            goto Lnot;
+        t = t->copy();
+        ((TypeNext *)t)->next = n;
+    }
+    //printf("strip %s\n", t->toChars());
+Lnot:
+    return t;
+}
+
+/************************************
+ */
+
+Type *Type::merge()
+{
+    if (ty == Terror) return this;
+    if (ty == Ttypeof) return this;
+    if (ty == Tident) return this;
+    if (ty == Tinstance) return this;
+    if (ty == Taarray && !((TypeAArray *)this)->index->merge()->deco)
+        return this;
+    if (ty != Tenum && nextOf() && !nextOf()->deco)
+        return this;
+
+    //printf("merge(%s)\n", toChars());
+    Type *t = this;
+    assert(t);
+    if (!deco)
+    {
+        OutBuffer buf;
+        buf.reserve(32);
+
+        mangleToBuffer(this, &buf);
+
+        StringValue *sv = stringtable.update((char *)buf.data, buf.offset);
+        if (sv->ptrvalue)
+        {
+            t = (Type *) sv->ptrvalue;
+#ifdef DEBUG
+            if (!t->deco)
+                printf("t = %s\n", t->toChars());
+#endif
+            assert(t->deco);
+            //printf("old value, deco = '%s' %p\n", t->deco, t->deco);
+        }
+        else
+        {
+            sv->ptrvalue = (char *)(t = stripDefaultArgs(t));
+            deco = t->deco = (char *)sv->toDchars();
+            //printf("new value, deco = '%s' %p\n", t->deco, t->deco);
+        }
+    }
+    return t;
+}
+
+/*************************************
+ * This version does a merge even if the deco is already computed.
+ * Necessary for types that have a deco, but are not merged.
+ */
+Type *Type::merge2()
+{
+    //printf("merge2(%s)\n", toChars());
+    Type *t = this;
+    assert(t);
+    if (!t->deco)
+        return t->merge();
+
+    StringValue *sv = stringtable.lookup((char *)t->deco, strlen(t->deco));
+    if (sv && sv->ptrvalue)
+    {   t = (Type *) sv->ptrvalue;
+        assert(t->deco);
+    }
+    else
+        assert(0);
+    return t;
+}
+
+bool Type::isintegral()
+{
+    return false;
+}
+
+bool Type::isfloating()
+{
+    return false;
+}
+
+bool Type::isreal()
+{
+    return false;
+}
+
+bool Type::isimaginary()
+{
+    return false;
+}
+
+bool Type::iscomplex()
+{
+    return false;
+}
+
+bool Type::isscalar()
+{
+    return false;
+}
+
+bool Type::isunsigned()
+{
+    return false;
+}
+
+ClassDeclaration *Type::isClassHandle()
+{
+    return NULL;
+}
+
+bool Type::isscope()
+{
+    return false;
+}
+
+bool Type::isString()
+{
+    return false;
+}
+
+/**************************
+ * When T is mutable,
+ * Given:
+ *      T a, b;
+ * Can we bitwise assign:
+ *      a = b;
+ * ?
+ */
+bool Type::isAssignable()
+{
+    return true;
+}
+
+/**************************
+ * Returns true if T can be converted to boolean value.
+ */
+bool Type::isBoolean()
+{
+    return isscalar();
+}
+
+/********************************
+ * true if when type goes out of scope, it needs a destructor applied.
+ * Only applies to value types, not ref types.
+ */
+bool Type::needsDestruction()
+{
+    return false;
+}
+
+/*********************************
+ *
+ */
+
+bool Type::needsNested()
+{
+    return false;
+}
+
+/*********************************
+ * Check type to see if it is based on a deprecated symbol.
+ */
+
+void Type::checkDeprecated(Loc loc, Scope *sc)
+{
+    Dsymbol *s = toDsymbol(sc);
+
+    if (s)
+        s->checkDeprecated(loc, sc);
+}
+
+
+Expression *Type::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("Type::defaultInit() '%s'\n", toChars());
+#endif
+    return NULL;
+}
+
+/***************************************
+ * Use when we prefer the default initializer to be a literal,
+ * rather than a global immutable variable.
+ */
+Expression *Type::defaultInitLiteral(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("Type::defaultInitLiteral() '%s'\n", toChars());
+#endif
+    return defaultInit(loc);
+}
+
+bool Type::isZeroInit(Loc loc)
+{
+    return false;           // assume not
+}
+
+bool Type::isBaseOf(Type *t, int *poffset)
+{
+    return 0;           // assume not
+}
+
+/********************************
+ * Determine if 'this' can be implicitly converted
+ * to type 'to'.
+ * Returns:
+ *      MATCHnomatch, MATCHconvert, MATCHconst, MATCHexact
+ */
+
+MATCH Type::implicitConvTo(Type *to)
+{
+    //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
+    //printf("from: %s\n", toChars());
+    //printf("to  : %s\n", to->toChars());
+    if (this->equals(to))
+        return MATCHexact;
+    return MATCHnomatch;
+}
+
+/*******************************
+ * Determine if converting 'this' to 'to' is an identity operation,
+ * a conversion to const operation, or the types aren't the same.
+ * Returns:
+ *      MATCHexact      'this' == 'to'
+ *      MATCHconst      'to' is const
+ *      MATCHnomatch    conversion to mutable or invariant
+ */
+
+MATCH Type::constConv(Type *to)
+{
+    //printf("Type::constConv(this = %s, to = %s)\n", toChars(), to->toChars());
+    if (equals(to))
+        return MATCHexact;
+    if (ty == to->ty && MODimplicitConv(mod, to->mod))
+        return MATCHconst;
+    return MATCHnomatch;
+}
+
+/***************************************
+ * Return MOD bits matching this type to wild parameter type (tprm).
+ */
+
+unsigned char Type::deduceWild(Type *t, bool isRef)
+{
+    //printf("Type::deduceWild this = '%s', tprm = '%s'\n", toChars(), tprm->toChars());
+
+    if (t->isWild())
+    {
+        if (isImmutable())
+            return MODimmutable;
+        else if (isWildConst())
+        {
+            if (t->isWildConst())
+                return MODwild;
+            else
+                return MODwildconst;
+        }
+        else if (isWild())
+            return MODwild;
+        else if (isConst())
+            return MODconst;
+        else if (isMutable())
+            return MODmutable;
+        else
+            assert(0);
+    }
+    return 0;
+}
+
+Type *Type::unqualify(unsigned m)
+{
+    Type *t = mutableOf()->unSharedOf();
+
+    Type *tn = ty == Tenum ? NULL : nextOf();
+    if (tn && tn->ty != Tfunction)
+    {
+        Type *utn = tn->unqualify(m);
+        if (utn != tn)
+        {
+            if (ty == Tpointer)
+                t = utn->pointerTo();
+            else if (ty == Tarray)
+                t = utn->arrayOf();
+            else if (ty == Tsarray)
+                t = new TypeSArray(utn, ((TypeSArray *)this)->dim);
+            else if (ty == Taarray)
+            {
+                t = new TypeAArray(utn, ((TypeAArray *)this)->index);
+                ((TypeAArray *)t)->sc = ((TypeAArray *)this)->sc;   // duplicate scope
+            }
+            else
+                assert(0);
+
+            t = t->merge();
+        }
+    }
+    t = t->addMod(mod & ~m);
+    return t;
+}
+
+Type *Type::substWildTo(unsigned mod)
+{
+    //printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod);
+    Type *t;
+
+    if (Type *tn = nextOf())
+    {
+        // substitution has no effect on function pointer type.
+        if (ty == Tpointer && tn->ty == Tfunction)
+        {
+            t = this;
+            goto L1;
+        }
+
+        t = tn->substWildTo(mod);
+        if (t == tn)
+            t = this;
+        else
+        {
+            if (ty == Tpointer)
+                t = t->pointerTo();
+            else if (ty == Tarray)
+                t = t->arrayOf();
+            else if (ty == Tsarray)
+                t = new TypeSArray(t, ((TypeSArray *)this)->dim->syntaxCopy());
+            else if (ty == Taarray)
+            {
+                t = new TypeAArray(t, ((TypeAArray *)this)->index->syntaxCopy());
+                ((TypeAArray *)t)->sc = ((TypeAArray *)this)->sc;   // duplicate scope
+            }
+            else if (ty == Tdelegate)
+            {
+                t = new TypeDelegate(t);
+            }
+            else
+                assert(0);
+
+            t = t->merge();
+        }
+    }
+    else
+        t = this;
+
+L1:
+    if (isWild())
+    {
+        if (mod == MODimmutable)
+        {
+            t = t->immutableOf();
+        }
+        else if (mod == MODwildconst)
+        {
+            t = t->wildConstOf();
+        }
+        else if (mod == MODwild)
+        {
+            if (isWildConst())
+                t = t->wildConstOf();
+            else
+                t = t->wildOf();
+        }
+        else if (mod == MODconst)
+        {
+            t = t->constOf();
+        }
+        else
+        {
+            if (isWildConst())
+                t = t->constOf();
+            else
+                t = t->mutableOf();
+        }
+    }
+    if (isConst())
+        t = t->addMod(MODconst);
+    if (isShared())
+        t = t->addMod(MODshared);
+
+    //printf("-Type::substWildTo t = %s\n", t->toChars());
+    return t;
+}
+
+Type *TypeFunction::substWildTo(unsigned)
+{
+    if (!iswild && !(mod & MODwild))
+        return this;
+
+    // Substitude inout qualifier of function type to mutable or immutable
+    // would break type system. Instead substitude inout to the most weak
+    // qualifer - const.
+    unsigned m = MODconst;
+
+    assert(next);
+    Type *tret = next->substWildTo(m);
+    Parameters *params = parameters;
+    if (mod & MODwild)
+        params = parameters->copy();
+    for (size_t i = 0; i < params->dim; i++)
+    {
+        Parameter *p = (*params)[i];
+        Type *t = p->type->substWildTo(m);
+        if (t == p->type)
+            continue;
+        if (params == parameters)
+            params = parameters->copy();
+        (*params)[i] = new Parameter(p->storageClass, t, NULL, NULL);
+    }
+    if (next == tret && params == parameters)
+        return this;
+
+    // Similar to TypeFunction::syntaxCopy;
+    TypeFunction *t = new TypeFunction(params, tret, varargs, linkage);
+    t->mod = ((mod & MODwild) ? (mod & ~MODwild) | MODconst : mod);
+    t->isnothrow = isnothrow;
+    t->isnogc = isnogc;
+    t->purity = purity;
+    t->isproperty = isproperty;
+    t->isref = isref;
+    t->isreturn = isreturn;
+    t->isscope = isscope;
+    t->isscopeinferred = isscopeinferred;
+    t->iswild = 0;
+    t->trust = trust;
+    t->fargs = fargs;
+    return t->merge();
+}
+
+/**************************
+ * Return type with the top level of it being mutable.
+ */
+Type *Type::toHeadMutable()
+{
+    if (!mod)
+        return this;
+    return mutableOf();
+}
+
+/***************************************
+ * Calculate built-in properties which just the type is necessary.
+ *
+ * If flag & 1, don't report "not a property" error and just return NULL.
+ */
+Expression *Type::getProperty(Loc loc, Identifier *ident, int flag)
+{
+    Expression *e;
+
+#if LOGDOTEXP
+    printf("Type::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars());
+#endif
+    if (ident == Id::__sizeof)
+    {
+        d_uns64 sz = size(loc);
+        if (sz == SIZE_INVALID)
+            return new ErrorExp();
+        e = new IntegerExp(loc, sz, Type::tsize_t);
+    }
+    else if (ident == Id::__xalignof)
+    {
+        e = new IntegerExp(loc, alignsize(), Type::tsize_t);
+    }
+    else if (ident == Id::_init)
+    {
+        Type *tb = toBasetype();
+        e = defaultInitLiteral(loc);
+        if (tb->ty == Tstruct && tb->needsNested())
+        {
+            StructLiteralExp *se = (StructLiteralExp *)e;
+            se->useStaticInit = true;
+        }
+    }
+    else if (ident == Id::_mangleof)
+    {
+        if (!deco)
+        {
+            error(loc, "forward reference of type %s.mangleof", toChars());
+            e = new ErrorExp();
+        }
+        else
+        {
+            e = new StringExp(loc, (char *)deco, strlen(deco));
+            Scope sc;
+            e = ::semantic(e, &sc);
+        }
+    }
+    else if (ident == Id::stringof)
+    {
+        const char *s = toChars();
+        e = new StringExp(loc, (char *)s, strlen(s));
+        Scope sc;
+        e = ::semantic(e, &sc);
+    }
+    else if (flag && this != Type::terror)
+    {
+        return NULL;
+    }
+    else
+    {
+        Dsymbol *s = NULL;
+        if (ty == Tstruct || ty == Tclass || ty == Tenum)
+            s = toDsymbol(NULL);
+        if (s)
+            s = s->search_correct(ident);
+        if (this != Type::terror)
+        {
+            if (s)
+                error(loc, "no property '%s' for type '%s', did you mean '%s'?", ident->toChars(), toChars(), s->toChars());
+            else
+                error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars());
+        }
+        e = new ErrorExp();
+    }
+    return e;
+}
+
+/***************************************
+ * Access the members of the object e. This type is same as e->type.
+ *
+ * If flag & 1, don't report "not a property" error and just return NULL.
+ */
+Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+    VarDeclaration *v = NULL;
+
+#if LOGDOTEXP
+    printf("Type::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    Expression *ex = e;
+    while (ex->op == TOKcomma)
+        ex = ((CommaExp *)ex)->e2;
+    if (ex->op == TOKdotvar)
+    {
+        DotVarExp *dv = (DotVarExp *)ex;
+        v = dv->var->isVarDeclaration();
+    }
+    else if (ex->op == TOKvar)
+    {
+        VarExp *ve = (VarExp *)ex;
+        v = ve->var->isVarDeclaration();
+    }
+    if (v)
+    {
+        if (ident == Id::offsetof)
+        {
+            if (v->isField())
+            {
+                AggregateDeclaration *ad = v->toParent()->isAggregateDeclaration();
+                ad->size(e->loc);
+                if (ad->sizeok != SIZEOKdone)
+                    return new ErrorExp();
+                e = new IntegerExp(e->loc, v->offset, Type::tsize_t);
+                return e;
+            }
+        }
+        else if (ident == Id::_init)
+        {
+            Type *tb = toBasetype();
+            e = defaultInitLiteral(e->loc);
+            if (tb->ty == Tstruct && tb->needsNested())
+            {
+                StructLiteralExp *se = (StructLiteralExp *)e;
+                se->useStaticInit = true;
+            }
+            goto Lreturn;
+        }
+    }
+    if (ident == Id::stringof)
+    {
+        /* Bugzilla 3796: this should demangle e->type->deco rather than
+         * pretty-printing the type.
+         */
+        const char *s = e->toChars();
+        e = new StringExp(e->loc, (char *)s, strlen(s));
+    }
+    else
+        e = getProperty(e->loc, ident, flag & 1);
+
+Lreturn:
+    if (!(flag & 1) || e)
+        e = ::semantic(e, sc);
+    return e;
+}
+
+/************************************
+ * Return alignment to use for this type.
+ */
+
+structalign_t Type::alignment()
+{
+    return STRUCTALIGN_DEFAULT;
+}
+
+/***************************************
+ * Figures out what to do with an undefined member reference
+ * for classes and structs.
+ *
+ * If flag & 1, don't report "not a property" error and just return NULL.
+ */
+Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+    assert(ty == Tstruct || ty == Tclass);
+    AggregateDeclaration *sym = toDsymbol(sc)->isAggregateDeclaration();
+    assert(sym);
+
+    if (ident != Id::__sizeof &&
+        ident != Id::__xalignof &&
+        ident != Id::_init &&
+        ident != Id::_mangleof &&
+        ident != Id::stringof &&
+        ident != Id::offsetof &&
+        // Bugzilla 15045: Don't forward special built-in member functions.
+        ident != Id::ctor &&
+        ident != Id::dtor &&
+        ident != Id::__xdtor &&
+        ident != Id::postblit &&
+        ident != Id::__xpostblit)
+    {
+        /* Look for overloaded opDot() to see if we should forward request
+         * to it.
+         */
+        if (Dsymbol *fd = search_function(sym, Id::opDot))
+        {
+            /* Rewrite e.ident as:
+             *  e.opDot().ident
+             */
+            e = build_overload(e->loc, sc, e, NULL, fd);
+            e = new DotIdExp(e->loc, e, ident);
+            return ::semantic(e, sc);
+        }
+
+        /* Look for overloaded opDispatch to see if we should forward request
+         * to it.
+         */
+        if (Dsymbol *fd = search_function(sym, Id::opDispatch))
+        {
+            /* Rewrite e.ident as:
+             *  e.opDispatch!("ident")
+             */
+            TemplateDeclaration *td = fd->isTemplateDeclaration();
+            if (!td)
+            {
+                fd->error("must be a template opDispatch(string s), not a %s", fd->kind());
+                return new ErrorExp();
+            }
+            StringExp *se = new StringExp(e->loc, (char *)ident->toChars());
+            Objects *tiargs = new Objects();
+            tiargs->push(se);
+            DotTemplateInstanceExp *dti = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs);
+            dti->ti->tempdecl = td;
+
+            /* opDispatch, which doesn't need IFTI,  may occur instantiate error.
+             * It should be gagged if flag & 1.
+             * e.g.
+             *  template opDispatch(name) if (isValid!name) { ... }
+             */
+            unsigned errors = flag & 1 ? global.startGagging() : 0;
+            e = semanticY(dti, sc, 0);
+            if (flag & 1 && global.endGagging(errors))
+                e = NULL;
+            return e;
+        }
+
+        /* See if we should forward to the alias this.
+         */
+        if (sym->aliasthis)
+        {   /* Rewrite e.ident as:
+             *  e.aliasthis.ident
+             */
+            e = resolveAliasThis(sc, e);
+            DotIdExp *die = new DotIdExp(e->loc, e, ident);
+            return semanticY(die, sc, flag & 1);
+        }
+    }
+
+    return Type::dotExp(sc, e, ident, flag);
+}
+
+void Type::error(Loc loc, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::verror(loc, format, ap);
+    va_end( ap );
+}
+
+void Type::warning(Loc loc, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::vwarning(loc, format, ap);
+    va_end( ap );
+}
+
+Identifier *Type::getTypeInfoIdent()
+{
+    // _init_10TypeInfo_%s
+    OutBuffer buf;
+    buf.reserve(32);
+    mangleToBuffer(this, &buf);
+
+    size_t len = buf.offset;
+    buf.writeByte(0);
+
+    // Allocate buffer on stack, fail over to using malloc()
+    char namebuf[128];
+    size_t namelen = 19 + sizeof(len) * 3 + len + 1;
+    char *name = namelen <= sizeof(namebuf) ? namebuf : (char *)malloc(namelen);
+    assert(name);
+
+    sprintf(name, "_D%lluTypeInfo_%s6__initZ", (unsigned long long) 9 + len, buf.data);
+    //printf("%p, deco = %s, name = %s\n", this, deco, name);
+    assert(strlen(name) < namelen);     // don't overflow the buffer
+
+    size_t off = 0;
+#ifndef IN_GCC
+    if (global.params.isOSX || global.params.isWindows && !global.params.is64bit)
+        ++off;                 // C mangling will add '_' back in
+#endif
+    Identifier *id = Identifier::idPool(name + off);
+
+    if (name != namebuf)
+        free(name);
+    return id;
+}
+
+TypeBasic *Type::isTypeBasic()
+{
+    return NULL;
+}
+
+
+/***************************************
+ * Resolve 'this' type to either type, symbol, or expression.
+ * If errors happened, resolved to Type.terror.
+ */
+void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+    //printf("Type::resolve() %s, %d\n", toChars(), ty);
+    Type *t = semantic(loc, sc);
+    *pt = t;
+    *pe = NULL;
+    *ps = NULL;
+}
+
+/***************************************
+ * Normalize `e` as the result of Type::resolve() process.
+ */
+void Type::resolveExp(Expression *e, Type **pt, Expression **pe, Dsymbol **ps)
+{
+    *pt = NULL;
+    *pe = NULL;
+    *ps = NULL;
+
+    Dsymbol *s;
+    switch (e->op)
+    {
+        case TOKerror:
+            *pt = Type::terror;
+            return;
+
+        case TOKtype:
+            *pt = e->type;
+            return;
+
+        case TOKvar:
+            s = ((VarExp *)e)->var;
+            if (s->isVarDeclaration())
+                goto Ldefault;
+            //if (s->isOverDeclaration())
+            //    todo;
+            break;
+
+        case TOKtemplate:
+            // TemplateDeclaration
+            s = ((TemplateExp *)e)->td;
+            break;
+
+        case TOKimport:
+            s = ((ScopeExp *)e)->sds;
+            // TemplateDeclaration, TemplateInstance, Import, Package, Module
+            break;
+
+        case TOKfunction:
+            s = getDsymbol(e);
+            break;
+
+        //case TOKthis:
+        //case TOKsuper:
+
+        //case TOKtuple:
+
+        //case TOKoverloadset:
+
+        //case TOKdotvar:
+        //case TOKdottd:
+        //case TOKdotti:
+        //case TOKdottype:
+        //case TOKdot:
+
+        default:
+    Ldefault:
+            *pe = e;
+            return;
+    }
+
+    *ps = s;
+}
+
+/***************************************
+ * Return !=0 if the type or any of its subtypes is wild.
+ */
+
+int Type::hasWild() const
+{
+    return mod & MODwild;
+}
+
+/***************************************
+ * Return !=0 if type has pointers that need to
+ * be scanned by the GC during a collection cycle.
+ */
+bool Type::hasPointers()
+{
+    //printf("Type::hasPointers() %s, %d\n", toChars(), ty);
+    return false;
+}
+
+/*************************************
+ * Detect if type has pointer fields that are initialized to void.
+ * Local stack variables with such void fields can remain uninitialized,
+ * leading to pointer bugs.
+ * Returns:
+ *  true if so
+ */
+bool Type::hasVoidInitPointers()
+{
+    return false;
+}
+
+/*************************************
+ * If this is a type of something, return that something.
+ */
+
+Type *Type::nextOf()
+{
+    return NULL;
+}
+
+/*************************************
+ * If this is a type of static array, return its base element type.
+ */
+
+Type *Type::baseElemOf()
+{
+    Type *t = toBasetype();
+    while (t->ty == Tsarray)
+        t = ((TypeSArray *)t)->next->toBasetype();
+    return t;
+}
+
+/*************************************
+ * Bugzilla 14488: Check if the inner most base type is complex or imaginary.
+ * Should only give alerts when set to emit transitional messages.
+ */
+
+void Type::checkComplexTransition(Loc loc)
+{
+    Type *t = baseElemOf();
+    while (t->ty == Tpointer || t->ty == Tarray)
+        t = t->nextOf()->baseElemOf();
+
+    if (t->isimaginary() || t->iscomplex())
+    {
+        const char *p = loc.toChars();
+        Type *rt;
+        switch (t->ty)
+        {
+            case Tcomplex32:
+            case Timaginary32:
+                rt = Type::tfloat32; break;
+            case Tcomplex64:
+            case Timaginary64:
+                rt = Type::tfloat64; break;
+            case Tcomplex80:
+            case Timaginary80:
+                rt = Type::tfloat80; break;
+            default:
+                assert(0);
+        }
+        if (t->iscomplex())
+        {
+            fprintf(global.stdmsg, "%s: use of complex type '%s' is scheduled for deprecation, "
+                    "use 'std.complex.Complex!(%s)' instead\n", p ? p : "", toChars(), rt->toChars());
+        }
+        else
+        {
+            fprintf(global.stdmsg, "%s: use of imaginary type '%s' is scheduled for deprecation, "
+                    "use '%s' instead\n", p ? p : "", toChars(), rt->toChars());
+        }
+    }
+}
+
+/****************************************
+ * Return the mask that an integral type will
+ * fit into.
+ */
+uinteger_t Type::sizemask()
+{   uinteger_t m;
+
+    switch (toBasetype()->ty)
+    {
+        case Tbool:     m = 1;                          break;
+        case Tchar:
+        case Tint8:
+        case Tuns8:     m = 0xFF;                       break;
+        case Twchar:
+        case Tint16:
+        case Tuns16:    m = 0xFFFFUL;                   break;
+        case Tdchar:
+        case Tint32:
+        case Tuns32:    m = 0xFFFFFFFFUL;               break;
+        case Tint64:
+        case Tuns64:    m = 0xFFFFFFFFFFFFFFFFULL;      break;
+        default:
+                assert(0);
+    }
+    return m;
+}
+
+/* ============================= TypeError =========================== */
+
+TypeError::TypeError()
+        : Type(Terror)
+{
+}
+
+Type *TypeError::syntaxCopy()
+{
+    // No semantic analysis done, no need to copy
+    return this;
+}
+
+d_uns64 TypeError::size(Loc loc) { return SIZE_INVALID; }
+Expression *TypeError::getProperty(Loc loc, Identifier *ident, int flag) { return new ErrorExp(); }
+Expression *TypeError::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag) { return new ErrorExp(); }
+Expression *TypeError::defaultInit(Loc loc) { return new ErrorExp(); }
+Expression *TypeError::defaultInitLiteral(Loc loc) { return new ErrorExp(); }
+
+/* ============================= TypeNext =========================== */
+
+TypeNext::TypeNext(TY ty, Type *next)
+        : Type(ty)
+{
+    this->next = next;
+}
+
+void TypeNext::checkDeprecated(Loc loc, Scope *sc)
+{
+    Type::checkDeprecated(loc, sc);
+    if (next)   // next can be NULL if TypeFunction and auto return type
+        next->checkDeprecated(loc, sc);
+}
+
+int TypeNext::hasWild() const
+{
+    if (ty == Tfunction)
+        return 0;
+    if (ty == Tdelegate)
+        return Type::hasWild();
+    return mod & MODwild || (next && next->hasWild());
+}
+
+
+/*******************************
+ * For TypeFunction, nextOf() can return NULL if the function return
+ * type is meant to be inferred, and semantic() hasn't yet ben run
+ * on the function. After semantic(), it must no longer be NULL.
+ */
+
+Type *TypeNext::nextOf()
+{
+    return next;
+}
+
+Type *TypeNext::makeConst()
+{
+    //printf("TypeNext::makeConst() %p, %s\n", this, toChars());
+    if (cto)
+    {
+        assert(cto->mod == MODconst);
+        return cto;
+    }
+    TypeNext *t = (TypeNext *)Type::makeConst();
+    if (ty != Tfunction && next->ty != Tfunction &&
+        !next->isImmutable())
+    {
+        if (next->isShared())
+        {
+            if (next->isWild())
+                t->next = next->sharedWildConstOf();
+            else
+                t->next = next->sharedConstOf();
+        }
+        else
+        {
+            if (next->isWild())
+                t->next = next->wildConstOf();
+            else
+                t->next = next->constOf();
+        }
+    }
+    //printf("TypeNext::makeConst() returns %p, %s\n", t, t->toChars());
+    return t;
+}
+
+Type *TypeNext::makeImmutable()
+{
+    //printf("TypeNext::makeImmutable() %s\n", toChars());
+    if (ito)
+    {
+        assert(ito->isImmutable());
+        return ito;
+    }
+    TypeNext *t = (TypeNext *)Type::makeImmutable();
+    if (ty != Tfunction && next->ty != Tfunction &&
+        !next->isImmutable())
+    {
+        t->next = next->immutableOf();
+    }
+    return t;
+}
+
+Type *TypeNext::makeShared()
+{
+    //printf("TypeNext::makeShared() %s\n", toChars());
+    if (sto)
+    {
+        assert(sto->mod == MODshared);
+        return sto;
+    }
+    TypeNext *t = (TypeNext *)Type::makeShared();
+    if (ty != Tfunction && next->ty != Tfunction &&
+        !next->isImmutable())
+    {
+        if (next->isWild())
+        {
+            if (next->isConst())
+                t->next = next->sharedWildConstOf();
+            else
+                t->next = next->sharedWildOf();
+        }
+        else
+        {
+            if (next->isConst())
+                t->next = next->sharedConstOf();
+            else
+                t->next = next->sharedOf();
+        }
+    }
+    //printf("TypeNext::makeShared() returns %p, %s\n", t, t->toChars());
+    return t;
+}
+
+Type *TypeNext::makeSharedConst()
+{
+    //printf("TypeNext::makeSharedConst() %s\n", toChars());
+    if (scto)
+    {
+        assert(scto->mod == (MODshared | MODconst));
+        return scto;
+    }
+    TypeNext *t = (TypeNext *)Type::makeSharedConst();
+    if (ty != Tfunction && next->ty != Tfunction &&
+        !next->isImmutable())
+    {
+        if (next->isWild())
+            t->next = next->sharedWildConstOf();
+        else
+            t->next = next->sharedConstOf();
+    }
+    //printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t->toChars());
+    return t;
+}
+
+Type *TypeNext::makeWild()
+{
+    //printf("TypeNext::makeWild() %s\n", toChars());
+    if (wto)
+    {
+        assert(wto->mod == MODwild);
+        return wto;
+    }
+    TypeNext *t = (TypeNext *)Type::makeWild();
+    if (ty != Tfunction && next->ty != Tfunction &&
+        !next->isImmutable())
+    {
+        if (next->isShared())
+        {
+            if (next->isConst())
+                t->next = next->sharedWildConstOf();
+            else
+                t->next = next->sharedWildOf();
+        }
+        else
+        {
+            if (next->isConst())
+                t->next = next->wildConstOf();
+            else
+                t->next = next->wildOf();
+        }
+    }
+    //printf("TypeNext::makeWild() returns %p, %s\n", t, t->toChars());
+    return t;
+}
+
+Type *TypeNext::makeWildConst()
+{
+    //printf("TypeNext::makeWildConst() %s\n", toChars());
+    if (wcto)
+    {
+        assert(wcto->mod == MODwildconst);
+        return wcto;
+    }
+    TypeNext *t = (TypeNext *)Type::makeWildConst();
+    if (ty != Tfunction && next->ty != Tfunction &&
+        !next->isImmutable())
+    {
+        if (next->isShared())
+            t->next = next->sharedWildConstOf();
+        else
+            t->next = next->wildConstOf();
+    }
+    //printf("TypeNext::makeWildConst() returns %p, %s\n", t, t->toChars());
+    return t;
+}
+
+Type *TypeNext::makeSharedWild()
+{
+    //printf("TypeNext::makeSharedWild() %s\n", toChars());
+    if (swto)
+    {
+        assert(swto->isSharedWild());
+        return swto;
+    }
+    TypeNext *t = (TypeNext *)Type::makeSharedWild();
+    if (ty != Tfunction && next->ty != Tfunction &&
+        !next->isImmutable())
+    {
+        if (next->isConst())
+            t->next = next->sharedWildConstOf();
+        else
+            t->next = next->sharedWildOf();
+    }
+    //printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t->toChars());
+    return t;
+}
+
+Type *TypeNext::makeSharedWildConst()
+{
+    //printf("TypeNext::makeSharedWildConst() %s\n", toChars());
+    if (swcto)
+    {
+        assert(swcto->mod == (MODshared | MODwildconst));
+        return swcto;
+    }
+    TypeNext *t = (TypeNext *)Type::makeSharedWildConst();
+    if (ty != Tfunction && next->ty != Tfunction &&
+        !next->isImmutable())
+    {
+        t->next = next->sharedWildConstOf();
+    }
+    //printf("TypeNext::makeSharedWildConst() returns %p, %s\n", t, t->toChars());
+    return t;
+}
+
+Type *TypeNext::makeMutable()
+{
+    //printf("TypeNext::makeMutable() %p, %s\n", this, toChars());
+    TypeNext *t = (TypeNext *)Type::makeMutable();
+    if (ty == Tsarray)
+    {
+        t->next = next->mutableOf();
+    }
+    //printf("TypeNext::makeMutable() returns %p, %s\n", t, t->toChars());
+    return t;
+}
+
+MATCH TypeNext::constConv(Type *to)
+{
+    //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to->toChars());
+    if (equals(to))
+        return MATCHexact;
+
+    if (!(ty == to->ty && MODimplicitConv(mod, to->mod)))
+        return MATCHnomatch;
+
+    Type *tn = to->nextOf();
+    if (!(tn && next->ty == tn->ty))
+        return MATCHnomatch;
+
+    MATCH m;
+    if (to->isConst())  // whole tail const conversion
+    {   // Recursive shared level check
+        m = next->constConv(tn);
+        if (m == MATCHexact)
+            m = MATCHconst;
+    }
+    else
+    {   //printf("\tnext => %s, to->next => %s\n", next->toChars(), tn->toChars());
+        m = next->equals(tn) ? MATCHconst : MATCHnomatch;
+    }
+    return m;
+}
+
+unsigned char TypeNext::deduceWild(Type *t, bool isRef)
+{
+    if (ty == Tfunction)
+        return 0;
+
+    unsigned char wm;
+
+    Type *tn = t->nextOf();
+    if (!isRef && (ty == Tarray || ty == Tpointer) && tn)
+    {
+        wm = next->deduceWild(tn, true);
+        if (!wm)
+            wm = Type::deduceWild(t, true);
+    }
+    else
+    {
+        wm = Type::deduceWild(t, isRef);
+        if (!wm && tn)
+            wm = next->deduceWild(tn, true);
+    }
+
+    return wm;
+}
+
+
+void TypeNext::transitive()
+{
+    /* Invoke transitivity of type attributes
+     */
+    next = next->addMod(mod);
+}
+
+/* ============================= TypeBasic =========================== */
+
+#define TFLAGSintegral  1
+#define TFLAGSfloating  2
+#define TFLAGSunsigned  4
+#define TFLAGSreal      8
+#define TFLAGSimaginary 0x10
+#define TFLAGScomplex   0x20
+
+TypeBasic::TypeBasic(TY ty)
+        : Type(ty)
+{   const char *d;
+    unsigned flags;
+
+    flags = 0;
+    switch (ty)
+    {
+        case Tvoid:     d = Token::toChars(TOKvoid);
+                        break;
+
+        case Tint8:     d = Token::toChars(TOKint8);
+                        flags |= TFLAGSintegral;
+                        break;
+
+        case Tuns8:     d = Token::toChars(TOKuns8);
+                        flags |= TFLAGSintegral | TFLAGSunsigned;
+                        break;
+
+        case Tint16:    d = Token::toChars(TOKint16);
+                        flags |= TFLAGSintegral;
+                        break;
+
+        case Tuns16:    d = Token::toChars(TOKuns16);
+                        flags |= TFLAGSintegral | TFLAGSunsigned;
+                        break;
+
+        case Tint32:    d = Token::toChars(TOKint32);
+                        flags |= TFLAGSintegral;
+                        break;
+
+        case Tuns32:    d = Token::toChars(TOKuns32);
+                        flags |= TFLAGSintegral | TFLAGSunsigned;
+                        break;
+
+        case Tfloat32:  d = Token::toChars(TOKfloat32);
+                        flags |= TFLAGSfloating | TFLAGSreal;
+                        break;
+
+        case Tint64:    d = Token::toChars(TOKint64);
+                        flags |= TFLAGSintegral;
+                        break;
+
+        case Tuns64:    d = Token::toChars(TOKuns64);
+                        flags |= TFLAGSintegral | TFLAGSunsigned;
+                        break;
+
+        case Tint128:   d = Token::toChars(TOKint128);
+                        flags |= TFLAGSintegral;
+                        break;
+
+        case Tuns128:   d = Token::toChars(TOKuns128);
+                        flags |= TFLAGSintegral | TFLAGSunsigned;
+                        break;
+
+        case Tfloat64:  d = Token::toChars(TOKfloat64);
+                        flags |= TFLAGSfloating | TFLAGSreal;
+                        break;
+
+        case Tfloat80:  d = Token::toChars(TOKfloat80);
+                        flags |= TFLAGSfloating | TFLAGSreal;
+                        break;
+
+        case Timaginary32: d = Token::toChars(TOKimaginary32);
+                        flags |= TFLAGSfloating | TFLAGSimaginary;
+                        break;
+
+        case Timaginary64: d = Token::toChars(TOKimaginary64);
+                        flags |= TFLAGSfloating | TFLAGSimaginary;
+                        break;
+
+        case Timaginary80: d = Token::toChars(TOKimaginary80);
+                        flags |= TFLAGSfloating | TFLAGSimaginary;
+                        break;
+
+        case Tcomplex32: d = Token::toChars(TOKcomplex32);
+                        flags |= TFLAGSfloating | TFLAGScomplex;
+                        break;
+
+        case Tcomplex64: d = Token::toChars(TOKcomplex64);
+                        flags |= TFLAGSfloating | TFLAGScomplex;
+                        break;
+
+        case Tcomplex80: d = Token::toChars(TOKcomplex80);
+                        flags |= TFLAGSfloating | TFLAGScomplex;
+                        break;
+
+        case Tbool:     d = "bool";
+                        flags |= TFLAGSintegral | TFLAGSunsigned;
+                        break;
+
+        case Tchar:     d = Token::toChars(TOKchar);
+                        flags |= TFLAGSintegral | TFLAGSunsigned;
+                        break;
+
+        case Twchar:    d = Token::toChars(TOKwchar);
+                        flags |= TFLAGSintegral | TFLAGSunsigned;
+                        break;
+
+        case Tdchar:    d = Token::toChars(TOKdchar);
+                        flags |= TFLAGSintegral | TFLAGSunsigned;
+                        break;
+
+        default:        assert(0);
+    }
+    this->dstring = d;
+    this->flags = flags;
+    merge();
+}
+
+const char *TypeBasic::kind()
+{
+    return dstring;
+}
+
+Type *TypeBasic::syntaxCopy()
+{
+    // No semantic analysis done on basic types, no need to copy
+    return this;
+}
+
+d_uns64 TypeBasic::size(Loc loc)
+{   unsigned size;
+
+    //printf("TypeBasic::size()\n");
+    switch (ty)
+    {
+        case Tint8:
+        case Tuns8:     size = 1;       break;
+        case Tint16:
+        case Tuns16:    size = 2;       break;
+        case Tint32:
+        case Tuns32:
+        case Tfloat32:
+        case Timaginary32:
+                        size = 4;       break;
+        case Tint64:
+        case Tuns64:
+        case Tfloat64:
+        case Timaginary64:
+                        size = 8;       break;
+        case Tfloat80:
+        case Timaginary80:
+                        size = Target::realsize; break;
+        case Tcomplex32:
+                        size = 8;               break;
+        case Tcomplex64:
+        case Tint128:
+        case Tuns128:
+                        size = 16;              break;
+        case Tcomplex80:
+                        size = Target::realsize * 2; break;
+
+        case Tvoid:
+            //size = Type::size();      // error message
+            size = 1;
+            break;
+
+        case Tbool:     size = 1;               break;
+        case Tchar:     size = 1;               break;
+        case Twchar:    size = 2;               break;
+        case Tdchar:    size = 4;               break;
+
+        default:
+            assert(0);
+            break;
+    }
+    //printf("TypeBasic::size() = %d\n", size);
+    return size;
+}
+
+unsigned TypeBasic::alignsize()
+{
+    return Target::alignsize(this);
+}
+
+
+Expression *TypeBasic::getProperty(Loc loc, Identifier *ident, int flag)
+{
+    Expression *e;
+    dinteger_t ivalue;
+    real_t fvalue;
+
+    //printf("TypeBasic::getProperty('%s')\n", ident->toChars());
+    if (ident == Id::max)
+    {
+        switch (ty)
+        {
+        case Tint8:
+            ivalue = 0x7F;
+            goto Livalue;
+        case Tuns8:
+            ivalue = 0xFF;
+            goto Livalue;
+        case Tint16:
+            ivalue = 0x7FFFUL;
+            goto Livalue;
+        case Tuns16:
+            ivalue = 0xFFFFUL;
+            goto Livalue;
+        case Tint32:
+            ivalue = 0x7FFFFFFFUL;
+            goto Livalue;
+        case Tuns32:
+            ivalue = 0xFFFFFFFFUL;
+            goto Livalue;
+        case Tint64:
+            ivalue = 0x7FFFFFFFFFFFFFFFLL;
+            goto Livalue;
+        case Tuns64:
+            ivalue = 0xFFFFFFFFFFFFFFFFULL;
+            goto Livalue;
+        case Tbool:
+            ivalue = 1;
+            goto Livalue;
+        case Tchar:
+            ivalue = 0xFF;
+            goto Livalue;
+        case Twchar:
+            ivalue = 0xFFFFUL;
+            goto Livalue;
+        case Tdchar:
+            ivalue = 0x10FFFFUL;
+            goto Livalue;
+        case Tcomplex32:
+        case Timaginary32:
+        case Tfloat32:
+            fvalue = Target::FloatProperties::max;
+            goto Lfvalue;
+        case Tcomplex64:
+        case Timaginary64:
+        case Tfloat64:
+            fvalue = Target::DoubleProperties::max;
+            goto Lfvalue;
+        case Tcomplex80:
+        case Timaginary80:
+        case Tfloat80:
+            fvalue = Target::RealProperties::max;
+            goto Lfvalue;
+        }
+    }
+    else if (ident == Id::min)
+    {
+        switch (ty)
+        {
+        case Tint8:
+            ivalue = -128;
+            goto Livalue;
+        case Tuns8:
+            ivalue = 0;
+            goto Livalue;
+        case Tint16:
+            ivalue = -32768;
+            goto Livalue;
+        case Tuns16:
+            ivalue = 0;
+            goto Livalue;
+        case Tint32:
+            ivalue = -2147483647L - 1;
+            goto Livalue;
+        case Tuns32:
+            ivalue = 0;
+            goto Livalue;
+        case Tint64:
+            ivalue = (-9223372036854775807LL-1LL);
+            goto Livalue;
+        case Tuns64:
+            ivalue = 0;
+            goto Livalue;
+        case Tbool:
+            ivalue = 0;
+            goto Livalue;
+        case Tchar:
+            ivalue = 0;
+            goto Livalue;
+        case Twchar:
+            ivalue = 0;
+            goto Livalue;
+        case Tdchar:
+            ivalue = 0;
+            goto Livalue;
+
+        case Tcomplex32:
+        case Timaginary32:
+        case Tfloat32:
+        case Tcomplex64:
+        case Timaginary64:
+        case Tfloat64:
+        case Tcomplex80:
+        case Timaginary80:
+        case Tfloat80:
+            error(loc, "use .min_normal property instead of .min");
+            return new ErrorExp();
+        }
+    }
+    else if (ident == Id::min_normal)
+    {
+      Lmin_normal:
+        switch (ty)
+        {
+        case Tcomplex32:
+        case Timaginary32:
+        case Tfloat32:
+            fvalue = Target::FloatProperties::min_normal;
+            goto Lfvalue;
+        case Tcomplex64:
+        case Timaginary64:
+        case Tfloat64:
+            fvalue = Target::DoubleProperties::min_normal;
+            goto Lfvalue;
+        case Tcomplex80:
+        case Timaginary80:
+        case Tfloat80:
+            fvalue = Target::RealProperties::min_normal;
+            goto Lfvalue;
+        }
+    }
+    else if (ident == Id::nan)
+    {
+        switch (ty)
+        {
+        case Tcomplex32:
+        case Tcomplex64:
+        case Tcomplex80:
+        case Timaginary32:
+        case Timaginary64:
+        case Timaginary80:
+        case Tfloat32:
+        case Tfloat64:
+        case Tfloat80:
+            fvalue = Target::RealProperties::nan;
+            goto Lfvalue;
+        }
+    }
+    else if (ident == Id::infinity)
+    {
+        switch (ty)
+        {
+        case Tcomplex32:
+        case Tcomplex64:
+        case Tcomplex80:
+        case Timaginary32:
+        case Timaginary64:
+        case Timaginary80:
+        case Tfloat32:
+        case Tfloat64:
+        case Tfloat80:
+            fvalue = Target::RealProperties::infinity;
+            goto Lfvalue;
+        }
+    }
+    else if (ident == Id::dig)
+    {
+        switch (ty)
+        {
+        case Tcomplex32:
+        case Timaginary32:
+        case Tfloat32:
+            ivalue = Target::FloatProperties::dig;
+            goto Lint;
+        case Tcomplex64:
+        case Timaginary64:
+        case Tfloat64:
+            ivalue = Target::DoubleProperties::dig;
+            goto Lint;
+        case Tcomplex80:
+        case Timaginary80:
+        case Tfloat80:
+            ivalue = Target::RealProperties::dig;
+            goto Lint;
+        }
+    }
+    else if (ident == Id::epsilon)
+    {
+        switch (ty)
+        {
+        case Tcomplex32:
+        case Timaginary32:
+        case Tfloat32:
+            fvalue = Target::FloatProperties::epsilon;
+            goto Lfvalue;
+        case Tcomplex64:
+        case Timaginary64:
+        case Tfloat64:
+            fvalue = Target::DoubleProperties::epsilon;
+            goto Lfvalue;
+        case Tcomplex80:
+        case Timaginary80:
+        case Tfloat80:
+            fvalue = Target::RealProperties::epsilon;
+            goto Lfvalue;
+        }
+    }
+    else if (ident == Id::mant_dig)
+    {
+        switch (ty)
+        {
+        case Tcomplex32:
+        case Timaginary32:
+        case Tfloat32:
+            ivalue = Target::FloatProperties::mant_dig;
+            goto Lint;
+        case Tcomplex64:
+        case Timaginary64:
+        case Tfloat64:
+            ivalue = Target::DoubleProperties::mant_dig;
+            goto Lint;
+        case Tcomplex80:
+        case Timaginary80:
+        case Tfloat80:
+            ivalue = Target::RealProperties::mant_dig;
+            goto Lint;
+        }
+    }
+    else if (ident == Id::max_10_exp)
+    {
+        switch (ty)
+        {
+        case Tcomplex32:
+        case Timaginary32:
+        case Tfloat32:
+            ivalue = Target::FloatProperties::max_10_exp;
+            goto Lint;
+        case Tcomplex64:
+        case Timaginary64:
+        case Tfloat64:
+            ivalue = Target::DoubleProperties::max_10_exp;
+            goto Lint;
+        case Tcomplex80:
+        case Timaginary80:
+        case Tfloat80:
+            ivalue = Target::RealProperties::max_10_exp;
+            goto Lint;
+        }
+    }
+    else if (ident == Id::max_exp)
+    {
+        switch (ty)
+        {
+        case Tcomplex32:
+        case Timaginary32:
+        case Tfloat32:
+            ivalue = Target::FloatProperties::max_exp;
+            goto Lint;
+        case Tcomplex64:
+        case Timaginary64:
+        case Tfloat64:
+            ivalue = Target::DoubleProperties::max_exp;
+            goto Lint;
+        case Tcomplex80:
+        case Timaginary80:
+        case Tfloat80:
+            ivalue = Target::RealProperties::max_exp;
+            goto Lint;
+        }
+    }
+    else if (ident == Id::min_10_exp)
+    {
+        switch (ty)
+        {
+        case Tcomplex32:
+        case Timaginary32:
+        case Tfloat32:
+            ivalue = Target::FloatProperties::min_10_exp;
+            goto Lint;
+        case Tcomplex64:
+        case Timaginary64:
+        case Tfloat64:
+            ivalue = Target::DoubleProperties::min_10_exp;
+            goto Lint;
+        case Tcomplex80:
+        case Timaginary80:
+        case Tfloat80:
+            ivalue = Target::RealProperties::min_10_exp;
+            goto Lint;
+        }
+    }
+    else if (ident == Id::min_exp)
+    {
+        switch (ty)
+        {
+        case Tcomplex32:
+        case Timaginary32:
+        case Tfloat32:
+            ivalue = Target::FloatProperties::min_exp;
+            goto Lint;
+        case Tcomplex64:
+        case Timaginary64:
+        case Tfloat64:
+            ivalue = Target::DoubleProperties::min_exp;
+            goto Lint;
+        case Tcomplex80:
+        case Timaginary80:
+        case Tfloat80:
+            ivalue = Target::RealProperties::min_exp;
+            goto Lint;
+        }
+    }
+
+    return Type::getProperty(loc, ident, flag);
+
+Livalue:
+    e = new IntegerExp(loc, ivalue, this);
+    return e;
+
+Lfvalue:
+    if (isreal() || isimaginary())
+        e = new RealExp(loc, fvalue, this);
+    else
+    {
+        complex_t cvalue = complex_t(fvalue, fvalue);
+        //for (int i = 0; i < 20; i++)
+        //    printf("%02x ", ((unsigned char *)&cvalue)[i]);
+        //printf("\n");
+        e = new ComplexExp(loc, cvalue, this);
+    }
+    return e;
+
+Lint:
+    e = new IntegerExp(loc, ivalue, Type::tint32);
+    return e;
+}
+
+Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+#if LOGDOTEXP
+    printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    Type *t;
+
+    if (ident == Id::re)
+    {
+        switch (ty)
+        {
+            case Tcomplex32:    t = tfloat32;           goto L1;
+            case Tcomplex64:    t = tfloat64;           goto L1;
+            case Tcomplex80:    t = tfloat80;           goto L1;
+            L1:
+                e = e->castTo(sc, t);
+                break;
+
+            case Tfloat32:
+            case Tfloat64:
+            case Tfloat80:
+                break;
+
+            case Timaginary32:  t = tfloat32;           goto L2;
+            case Timaginary64:  t = tfloat64;           goto L2;
+            case Timaginary80:  t = tfloat80;           goto L2;
+            L2:
+                e = new RealExp(e->loc, CTFloat::zero, t);
+                break;
+
+            default:
+                e = Type::getProperty(e->loc, ident, flag);
+                break;
+        }
+    }
+    else if (ident == Id::im)
+    {   Type *t2;
+
+        switch (ty)
+        {
+            case Tcomplex32:    t = timaginary32;       t2 = tfloat32;  goto L3;
+            case Tcomplex64:    t = timaginary64;       t2 = tfloat64;  goto L3;
+            case Tcomplex80:    t = timaginary80;       t2 = tfloat80;  goto L3;
+            L3:
+                e = e->castTo(sc, t);
+                e->type = t2;
+                break;
+
+            case Timaginary32:  t = tfloat32;   goto L4;
+            case Timaginary64:  t = tfloat64;   goto L4;
+            case Timaginary80:  t = tfloat80;   goto L4;
+            L4:
+                e = e->copy();
+                e->type = t;
+                break;
+
+            case Tfloat32:
+            case Tfloat64:
+            case Tfloat80:
+                e = new RealExp(e->loc, CTFloat::zero, this);
+                break;
+
+            default:
+                e = Type::getProperty(e->loc, ident, flag);
+                break;
+        }
+    }
+    else
+    {
+        return Type::dotExp(sc, e, ident, flag);
+    }
+    if (!(flag & 1) || e)
+        e = ::semantic(e, sc);
+    return e;
+}
+
+Expression *TypeBasic::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeBasic::defaultInit() '%s'\n", toChars());
+#endif
+    dinteger_t value = 0;
+
+    switch (ty)
+    {
+        case Tchar:
+            value = 0xFF;
+            break;
+
+        case Twchar:
+        case Tdchar:
+            value = 0xFFFF;
+            break;
+
+        case Timaginary32:
+        case Timaginary64:
+        case Timaginary80:
+        case Tfloat32:
+        case Tfloat64:
+        case Tfloat80:
+            return new RealExp(loc, Target::RealProperties::snan, this);
+
+        case Tcomplex32:
+        case Tcomplex64:
+        case Tcomplex80:
+        {   // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
+            complex_t cvalue = complex_t(Target::RealProperties::snan, Target::RealProperties::snan);
+            return new ComplexExp(loc, cvalue, this);
+        }
+
+        case Tvoid:
+            error(loc, "void does not have a default initializer");
+            return new ErrorExp();
+    }
+    return new IntegerExp(loc, value, this);
+}
+
+bool TypeBasic::isZeroInit(Loc loc)
+{
+    switch (ty)
+    {
+        case Tchar:
+        case Twchar:
+        case Tdchar:
+        case Timaginary32:
+        case Timaginary64:
+        case Timaginary80:
+        case Tfloat32:
+        case Tfloat64:
+        case Tfloat80:
+        case Tcomplex32:
+        case Tcomplex64:
+        case Tcomplex80:
+            return false;       // no
+        default:
+            return true;        // yes
+    }
+}
+
+bool TypeBasic::isintegral()
+{
+    //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags);
+    return (flags & TFLAGSintegral) != 0;
+}
+
+bool TypeBasic::isfloating()
+{
+    return (flags & TFLAGSfloating) != 0;
+}
+
+bool TypeBasic::isreal()
+{
+    return (flags & TFLAGSreal) != 0;
+}
+
+bool TypeBasic::isimaginary()
+{
+    return (flags & TFLAGSimaginary) != 0;
+}
+
+bool TypeBasic::iscomplex()
+{
+    return (flags & TFLAGScomplex) != 0;
+}
+
+bool TypeBasic::isunsigned()
+{
+    return (flags & TFLAGSunsigned) != 0;
+}
+
+bool TypeBasic::isscalar()
+{
+    return (flags & (TFLAGSintegral | TFLAGSfloating)) != 0;
+}
+
+MATCH TypeBasic::implicitConvTo(Type *to)
+{
+    //printf("TypeBasic::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
+    if (this == to)
+        return MATCHexact;
+
+    if (ty == to->ty)
+    {
+        if (mod == to->mod)
+            return MATCHexact;
+        else if (MODimplicitConv(mod, to->mod))
+            return MATCHconst;
+        else if (!((mod ^ to->mod) & MODshared))    // for wild matching
+            return MATCHconst;
+        else
+            return MATCHconvert;
+    }
+
+    if (ty == Tvoid || to->ty == Tvoid)
+        return MATCHnomatch;
+    if (to->ty == Tbool)
+        return MATCHnomatch;
+
+    TypeBasic *tob;
+    if (to->ty == Tvector && to->deco)
+    {
+        TypeVector *tv = (TypeVector *)to;
+        tob = tv->elementType();
+    }
+    else
+        tob = to->isTypeBasic();
+    if (!tob)
+        return MATCHnomatch;
+
+    if (flags & TFLAGSintegral)
+    {
+        // Disallow implicit conversion of integers to imaginary or complex
+        if (tob->flags & (TFLAGSimaginary | TFLAGScomplex))
+            return MATCHnomatch;
+
+        // If converting from integral to integral
+        if (tob->flags & TFLAGSintegral)
+        {   d_uns64 sz = size(Loc());
+            d_uns64 tosz = tob->size(Loc());
+
+            /* Can't convert to smaller size
+             */
+            if (sz > tosz)
+                return MATCHnomatch;
+
+            /* Can't change sign if same size
+             */
+            /*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned)
+                return MATCHnomatch;*/
+        }
+    }
+    else if (flags & TFLAGSfloating)
+    {
+        // Disallow implicit conversion of floating point to integer
+        if (tob->flags & TFLAGSintegral)
+            return MATCHnomatch;
+
+        assert(tob->flags & TFLAGSfloating || to->ty == Tvector);
+
+        // Disallow implicit conversion from complex to non-complex
+        if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex))
+            return MATCHnomatch;
+
+        // Disallow implicit conversion of real or imaginary to complex
+        if (flags & (TFLAGSreal | TFLAGSimaginary) &&
+            tob->flags & TFLAGScomplex)
+            return MATCHnomatch;
+
+        // Disallow implicit conversion to-from real and imaginary
+        if ((flags & (TFLAGSreal | TFLAGSimaginary)) !=
+            (tob->flags & (TFLAGSreal | TFLAGSimaginary)))
+            return MATCHnomatch;
+    }
+    return MATCHconvert;
+}
+
+TypeBasic *TypeBasic::isTypeBasic()
+{
+    return (TypeBasic *)this;
+}
+
+/* ============================= TypeVector =========================== */
+
+/* The basetype must be one of:
+ *   byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2]
+ * For AVX:
+ *   byte[32],ubyte[32],short[16],ushort[16],int[8],uint[8],long[4],ulong[4],float[8],double[4]
+ */
+TypeVector::TypeVector(Loc loc, Type *basetype)
+        : Type(Tvector)
+{
+    this->basetype = basetype;
+}
+
+TypeVector *TypeVector::create(Loc loc, Type *basetype)
+{
+    return new TypeVector(loc, basetype);
+}
+
+const char *TypeVector::kind()
+{
+    return "vector";
+}
+
+Type *TypeVector::syntaxCopy()
+{
+    return new TypeVector(Loc(), basetype->syntaxCopy());
+}
+
+Type *TypeVector::semantic(Loc loc, Scope *sc)
+{
+    unsigned int errors = global.errors;
+    basetype = basetype->semantic(loc, sc);
+    if (errors != global.errors)
+        return terror;
+    basetype = basetype->toBasetype()->mutableOf();
+    if (basetype->ty != Tsarray)
+    {
+        error(loc, "T in __vector(T) must be a static array, not %s", basetype->toChars());
+        return terror;
+    }
+    TypeSArray *t = (TypeSArray *)basetype;
+    int sz = (int)t->size(loc);
+    switch (Target::isVectorTypeSupported(sz, t->nextOf()))
+    {
+    case 0: // valid
+        break;
+    case 1: // no support at all
+        error(loc, "SIMD vector types not supported on this platform");
+        return terror;
+    case 2: // invalid size
+        error(loc, "%d byte vector type %s is not supported on this platform", sz, toChars());
+        return terror;
+    case 3: // invalid base type
+        error(loc, "vector type %s is not supported on this platform", toChars());
+        return terror;
+    default:
+        assert(0);
+    }
+    return merge();
+}
+
+TypeBasic *TypeVector::elementType()
+{
+    assert(basetype->ty == Tsarray);
+    TypeSArray *t = (TypeSArray *)basetype;
+    TypeBasic *tb = t->nextOf()->isTypeBasic();
+    assert(tb);
+    return tb;
+}
+
+bool TypeVector::isBoolean()
+{
+    return false;
+}
+
+d_uns64 TypeVector::size(Loc loc)
+{
+    return basetype->size();
+}
+
+unsigned TypeVector::alignsize()
+{
+    return (unsigned)basetype->size();
+}
+
+Expression *TypeVector::getProperty(Loc loc, Identifier *ident, int flag)
+{
+    return Type::getProperty(loc, ident, flag);
+}
+
+Expression *TypeVector::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+#if LOGDOTEXP
+    printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::ptr && e->op == TOKcall)
+    {
+        /* The trouble with TOKcall is the return ABI for float[4] is different from
+         * __vector(float[4]), and a type paint won't do.
+         */
+        e = new AddrExp(e->loc, e);
+        e = ::semantic(e, sc);
+        e = e->castTo(sc, basetype->nextOf()->pointerTo());
+        return e;
+    }
+    if (ident == Id::array)
+    {
+        //e = e->castTo(sc, basetype);
+        // Keep lvalue-ness
+        e = e->copy();
+        e->type = basetype;
+        return e;
+    }
+    if (ident == Id::_init || ident == Id::offsetof || ident == Id::stringof || ident == Id::__xalignof)
+    {
+        // init should return a new VectorExp (Bugzilla 12776)
+        // offsetof does not work on a cast expression, so use e directly
+        // stringof should not add a cast to the output
+        return Type::dotExp(sc, e, ident, flag);
+    }
+    return basetype->dotExp(sc, e->castTo(sc, basetype), ident, flag);
+}
+
+Expression *TypeVector::defaultInit(Loc loc)
+{
+    //printf("TypeVector::defaultInit()\n");
+    assert(basetype->ty == Tsarray);
+    Expression *e = basetype->defaultInit(loc);
+    VectorExp *ve = new VectorExp(loc, e, this);
+    ve->type = this;
+    ve->dim = (int)(basetype->size(loc) / elementType()->size(loc));
+    return ve;
+}
+
+Expression *TypeVector::defaultInitLiteral(Loc loc)
+{
+    //printf("TypeVector::defaultInitLiteral()\n");
+    assert(basetype->ty == Tsarray);
+    Expression *e = basetype->defaultInitLiteral(loc);
+    VectorExp *ve = new VectorExp(loc, e, this);
+    ve->type = this;
+    ve->dim = (int)(basetype->size(loc) / elementType()->size(loc));
+    return ve;
+}
+
+bool TypeVector::isZeroInit(Loc loc)
+{
+    return basetype->isZeroInit(loc);
+}
+
+bool TypeVector::isintegral()
+{
+    //printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags);
+    return basetype->nextOf()->isintegral();
+}
+
+bool TypeVector::isfloating()
+{
+    return basetype->nextOf()->isfloating();
+}
+
+bool TypeVector::isunsigned()
+{
+    return basetype->nextOf()->isunsigned();
+}
+
+bool TypeVector::isscalar()
+{
+    return basetype->nextOf()->isscalar();
+}
+
+MATCH TypeVector::implicitConvTo(Type *to)
+{
+    //printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
+    if (this == to)
+        return MATCHexact;
+    if (to->ty == Tvector)
+    {
+        TypeVector *tv = (TypeVector *)to;
+        assert(basetype->ty == Tsarray && tv->basetype->ty == Tsarray);
+
+        // Can't convert to a vector which has different size.
+        if (basetype->size() != tv->basetype->size())
+            return MATCHnomatch;
+
+        // Allow conversion to void[]
+        if (tv->basetype->nextOf()->ty == Tvoid)
+            return MATCHconvert;
+
+        // Otherwise implicitly convertible only if basetypes are.
+        return basetype->implicitConvTo(tv->basetype);
+    }
+    return MATCHnomatch;
+}
+
+/***************************** TypeArray *****************************/
+
+TypeArray::TypeArray(TY ty, Type *next)
+    : TypeNext(ty, next)
+{
+}
+
+Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+    Type *n = this->next->toBasetype();         // uncover any typedef's
+
+#if LOGDOTEXP
+    printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+
+    e = Type::dotExp(sc, e, ident, flag);
+
+    if (!(flag & 1) || e)
+        e = ::semantic(e, sc);
+    return e;
+
+Lerror:
+    return new ErrorExp();
+}
+
+
+/***************************** TypeSArray *****************************/
+
+TypeSArray::TypeSArray(Type *t, Expression *dim)
+    : TypeArray(Tsarray, t)
+{
+    //printf("TypeSArray(%s)\n", dim->toChars());
+    this->dim = dim;
+}
+
+const char *TypeSArray::kind()
+{
+    return "sarray";
+}
+
+Type *TypeSArray::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    Expression *e = dim->syntaxCopy();
+    t = new TypeSArray(t, e);
+    t->mod = mod;
+    return t;
+}
+
+d_uns64 TypeSArray::size(Loc loc)
+{
+    //printf("TypeSArray::size()\n");
+    dinteger_t sz;
+    if (!dim)
+        return Type::size(loc);
+    sz = dim->toInteger();
+
+    {
+        bool overflow = false;
+
+        sz = mulu(next->size(), sz, overflow);
+        if (overflow)
+            goto Loverflow;
+    }
+    if (sz > UINT32_MAX)
+        goto Loverflow;
+    return sz;
+
+Loverflow:
+    error(loc, "static array %s size overflowed to %lld", toChars(), (long long)sz);
+    return SIZE_INVALID;
+}
+
+unsigned TypeSArray::alignsize()
+{
+    return next->alignsize();
+}
+
+/**************************
+ * This evaluates exp while setting length to be the number
+ * of elements in the tuple t.
+ */
+Expression *semanticLength(Scope *sc, Type *t, Expression *exp)
+{
+    if (t->ty == Ttuple)
+    {
+        ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t);
+        sym->parent = sc->scopesym;
+        sc = sc->push(sym);
+
+        sc = sc->startCTFE();
+        exp = ::semantic(exp, sc);
+        sc = sc->endCTFE();
+
+        sc->pop();
+    }
+    else
+    {
+        sc = sc->startCTFE();
+        exp = ::semantic(exp, sc);
+        sc = sc->endCTFE();
+    }
+
+    return exp;
+}
+
+Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp)
+{
+    ScopeDsymbol *sym = new ArrayScopeSymbol(sc, s);
+    sym->parent = sc->scopesym;
+    sc = sc->push(sym);
+
+    sc = sc->startCTFE();
+    exp = ::semantic(exp, sc);
+    sc = sc->endCTFE();
+
+    sc->pop();
+    return exp;
+}
+
+void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+    //printf("TypeSArray::resolve() %s\n", toChars());
+    next->resolve(loc, sc, pe, pt, ps, intypeid);
+    //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
+    if (*pe)
+    {
+        // It's really an index expression
+        if (Dsymbol *s = getDsymbol(*pe))
+            *pe = new DsymbolExp(loc, s);
+        *pe = new ArrayExp(loc, *pe, dim);
+    }
+    else if (*ps)
+    {
+        Dsymbol *s = *ps;
+        TupleDeclaration *td = s->isTupleDeclaration();
+        if (td)
+        {
+            ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
+            sym->parent = sc->scopesym;
+            sc = sc->push(sym);
+            sc = sc->startCTFE();
+            dim = ::semantic(dim, sc);
+            sc = sc->endCTFE();
+            sc = sc->pop();
+
+            dim = dim->ctfeInterpret();
+            uinteger_t d = dim->toUInteger();
+
+            if (d >= td->objects->dim)
+            {
+                error(loc, "tuple index %llu exceeds length %u", d, td->objects->dim);
+                *ps = NULL;
+                *pt = Type::terror;
+                return;
+            }
+            RootObject *o = (*td->objects)[(size_t)d];
+            if (o->dyncast() == DYNCAST_DSYMBOL)
+            {
+                *ps = (Dsymbol *)o;
+                return;
+            }
+            if (o->dyncast() == DYNCAST_EXPRESSION)
+            {
+                Expression *e = (Expression *)o;
+                if (e->op == TOKdsymbol)
+                {
+                    *ps = ((DsymbolExp *)e)->s;
+                    *pe = NULL;
+                }
+                else
+                {
+                    *ps = NULL;
+                    *pe = e;
+                }
+                return;
+            }
+            if (o->dyncast() == DYNCAST_TYPE)
+            {
+                *ps = NULL;
+                *pt = ((Type *)o)->addMod(this->mod);
+                return;
+            }
+
+            /* Create a new TupleDeclaration which
+             * is a slice [d..d+1] out of the old one.
+             * Do it this way because TemplateInstance::semanticTiargs()
+             * can handle unresolved Objects this way.
+             */
+            Objects *objects = new Objects;
+            objects->setDim(1);
+            (*objects)[0] = o;
+
+            TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
+            *ps = tds;
+        }
+        else
+            goto Ldefault;
+    }
+    else
+    {
+        if ((*pt)->ty != Terror)
+            next = *pt;     // prevent re-running semantic() on 'next'
+     Ldefault:
+        Type::resolve(loc, sc, pe, pt, ps, intypeid);
+    }
+}
+
+Type *TypeSArray::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeSArray::semantic() %s\n", toChars());
+
+    Type *t;
+    Expression *e;
+    Dsymbol *s;
+    next->resolve(loc, sc, &e, &t, &s);
+    if (dim && s && s->isTupleDeclaration())
+    {   TupleDeclaration *sd = s->isTupleDeclaration();
+
+        dim = semanticLength(sc, sd, dim);
+        dim = dim->ctfeInterpret();
+        uinteger_t d = dim->toUInteger();
+
+        if (d >= sd->objects->dim)
+        {   error(loc, "tuple index %llu exceeds %u", d, sd->objects->dim);
+            return Type::terror;
+        }
+        RootObject *o = (*sd->objects)[(size_t)d];
+        if (o->dyncast() != DYNCAST_TYPE)
+        {   error(loc, "%s is not a type", toChars());
+            return Type::terror;
+        }
+        t = ((Type *)o)->addMod(this->mod);
+        return t;
+    }
+
+    Type *tn = next->semantic(loc, sc);
+    if (tn->ty == Terror)
+        return terror;
+
+    Type *tbn = tn->toBasetype();
+
+    if (dim)
+    {
+        unsigned int errors = global.errors;
+        dim = semanticLength(sc, tbn, dim);
+        if (errors != global.errors)
+            goto Lerror;
+
+        dim = dim->optimize(WANTvalue);
+        dim = dim->ctfeInterpret();
+        if (dim->op == TOKerror)
+            goto Lerror;
+        errors = global.errors;
+        dinteger_t d1 = dim->toInteger();
+        if (errors != global.errors)
+            goto Lerror;
+
+        dim = dim->implicitCastTo(sc, tsize_t);
+        dim = dim->optimize(WANTvalue);
+        if (dim->op == TOKerror)
+            goto Lerror;
+        errors = global.errors;
+        dinteger_t d2 = dim->toInteger();
+        if (errors != global.errors)
+            goto Lerror;
+
+        if (dim->op == TOKerror)
+            goto Lerror;
+
+        if (d1 != d2)
+        {
+        Loverflow:
+            error(loc, "%s size %llu * %llu exceeds 0x%llx size limit for static array",
+                toChars(), (unsigned long long)tbn->size(loc), (unsigned long long)d1, Target::maxStaticDataSize);
+            goto Lerror;
+        }
+
+        Type *tbx = tbn->baseElemOf();
+        if (tbx->ty == Tstruct && !((TypeStruct *)tbx)->sym->members ||
+            tbx->ty == Tenum && !((TypeEnum *)tbx)->sym->members)
+        {
+            /* To avoid meaningless error message, skip the total size limit check
+             * when the bottom of element type is opaque.
+             */
+        }
+        else if (tbn->isintegral() ||
+                 tbn->isfloating() ||
+                 tbn->ty == Tpointer ||
+                 tbn->ty == Tarray ||
+                 tbn->ty == Tsarray ||
+                 tbn->ty == Taarray ||
+                 (tbn->ty == Tstruct && (((TypeStruct *)tbn)->sym->sizeok == SIZEOKdone)) ||
+                 tbn->ty == Tclass)
+        {
+            /* Only do this for types that don't need to have semantic()
+             * run on them for the size, since they may be forward referenced.
+             */
+            bool overflow = false;
+            if (mulu(tbn->size(loc), d2, overflow) >= Target::maxStaticDataSize || overflow)
+                goto Loverflow;
+        }
+    }
+    switch (tbn->ty)
+    {
+        case Ttuple:
+        {   // Index the tuple to get the type
+            assert(dim);
+            TypeTuple *tt = (TypeTuple *)tbn;
+            uinteger_t d = dim->toUInteger();
+
+            if (d >= tt->arguments->dim)
+            {   error(loc, "tuple index %llu exceeds %u", d, tt->arguments->dim);
+                goto Lerror;
+            }
+            Type *telem = (*tt->arguments)[(size_t)d]->type;
+            return telem->addMod(this->mod);
+        }
+        case Tfunction:
+        case Tnone:
+            error(loc, "can't have array of %s", tbn->toChars());
+            goto Lerror;
+        default:
+            break;
+    }
+    if (tbn->isscope())
+    {   error(loc, "cannot have array of scope %s", tbn->toChars());
+        goto Lerror;
+    }
+
+    /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
+     * and const(T)[3] become const(T[3])
+     */
+    next = tn;
+    transitive();
+    t = addMod(tn->mod);
+
+    return t->merge();
+
+Lerror:
+    return Type::terror;
+}
+
+Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+#if LOGDOTEXP
+    printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::length)
+    {
+        Loc oldLoc = e->loc;
+        e = dim->copy();
+        e->loc = oldLoc;
+    }
+    else if (ident == Id::ptr)
+    {
+        if (e->op == TOKtype)
+        {
+            e->error("%s is not an expression", e->toChars());
+            return new ErrorExp();
+        }
+        e = e->castTo(sc, e->type->nextOf()->pointerTo());
+    }
+    else
+    {
+        e = TypeArray::dotExp(sc, e, ident, flag);
+    }
+    if (!(flag & 1) || e)
+        e = ::semantic(e, sc);
+    return e;
+}
+
+structalign_t TypeSArray::alignment()
+{
+    return next->alignment();
+}
+
+bool TypeSArray::isString()
+{
+    TY nty = next->toBasetype()->ty;
+    return nty == Tchar || nty == Twchar || nty == Tdchar;
+}
+
+MATCH TypeSArray::constConv(Type *to)
+{
+    if (to->ty == Tsarray)
+    {
+        TypeSArray *tsa = (TypeSArray *)to;
+        if (!dim->equals(tsa->dim))
+            return MATCHnomatch;
+    }
+    return TypeNext::constConv(to);
+}
+
+MATCH TypeSArray::implicitConvTo(Type *to)
+{
+    //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
+
+    if (to->ty == Tarray)
+    {
+        TypeDArray *ta = (TypeDArray *)to;
+
+        if (!MODimplicitConv(next->mod, ta->next->mod))
+            return MATCHnomatch;
+
+        /* Allow conversion to void[]
+         */
+        if (ta->next->ty == Tvoid)
+        {
+            return MATCHconvert;
+        }
+
+        MATCH m = next->constConv(ta->next);
+        if (m > MATCHnomatch)
+        {
+            return MATCHconvert;
+        }
+        return MATCHnomatch;
+    }
+
+    if (to->ty == Tsarray)
+    {
+        if (this == to)
+            return MATCHexact;
+
+        TypeSArray *tsa = (TypeSArray *)to;
+
+        if (dim->equals(tsa->dim))
+        {
+            /* Since static arrays are value types, allow
+             * conversions from const elements to non-const
+             * ones, just like we allow conversion from const int
+             * to int.
+             */
+            MATCH m = next->implicitConvTo(tsa->next);
+            if (m >= MATCHconst)
+            {
+                if (mod != to->mod)
+                    m = MATCHconst;
+                return m;
+            }
+        }
+    }
+    return MATCHnomatch;
+}
+
+Expression *TypeSArray::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeSArray::defaultInit() '%s'\n", toChars());
+#endif
+    if (next->ty == Tvoid)
+        return tuns8->defaultInit(loc);
+    else
+        return next->defaultInit(loc);
+}
+
+bool TypeSArray::isZeroInit(Loc loc)
+{
+    return next->isZeroInit(loc);
+}
+
+bool TypeSArray::needsDestruction()
+{
+    return next->needsDestruction();
+}
+
+/*********************************
+ *
+ */
+
+bool TypeSArray::needsNested()
+{
+    return next->needsNested();
+}
+
+Expression *TypeSArray::defaultInitLiteral(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars());
+#endif
+    size_t d = (size_t)dim->toInteger();
+    Expression *elementinit;
+    if (next->ty == Tvoid)
+        elementinit = tuns8->defaultInitLiteral(loc);
+    else
+        elementinit = next->defaultInitLiteral(loc);
+    Expressions *elements = new Expressions();
+    elements->setDim(d);
+    for (size_t i = 0; i < d; i++)
+        (*elements)[i] = NULL;
+    ArrayLiteralExp *ae = new ArrayLiteralExp(Loc(), elementinit, elements);
+    ae->type = this;
+    return ae;
+}
+
+bool TypeSArray::hasPointers()
+{
+    /* Don't want to do this, because:
+     *    struct S { T* array[0]; }
+     * may be a variable length struct.
+     */
+    //if (dim->toInteger() == 0)
+    //    return false;
+
+    if (next->ty == Tvoid)
+    {
+        // Arrays of void contain arbitrary data, which may include pointers
+        return true;
+    }
+    else
+        return next->hasPointers();
+}
+
+/***************************** TypeDArray *****************************/
+
+TypeDArray::TypeDArray(Type *t)
+    : TypeArray(Tarray, t)
+{
+    //printf("TypeDArray(t = %p)\n", t);
+}
+
+const char *TypeDArray::kind()
+{
+    return "darray";
+}
+
+Type *TypeDArray::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    if (t == next)
+        t = this;
+    else
+    {
+        t = new TypeDArray(t);
+        t->mod = mod;
+    }
+    return t;
+}
+
+d_uns64 TypeDArray::size(Loc loc)
+{
+    //printf("TypeDArray::size()\n");
+    return Target::ptrsize * 2;
+}
+
+unsigned TypeDArray::alignsize()
+{
+    // A DArray consists of two ptr-sized values, so align it on pointer size
+    // boundary
+    return Target::ptrsize;
+}
+
+Type *TypeDArray::semantic(Loc loc, Scope *sc)
+{
+    Type *tn = next->semantic(loc,sc);
+    Type *tbn = tn->toBasetype();
+    switch (tbn->ty)
+    {
+        case Ttuple:
+            return tbn;
+        case Tfunction:
+        case Tnone:
+            error(loc, "can't have array of %s", tbn->toChars());
+            return Type::terror;
+        case Terror:
+            return Type::terror;
+        default:
+            break;
+    }
+    if (tn->isscope())
+    {   error(loc, "cannot have array of scope %s", tn->toChars());
+        return Type::terror;
+    }
+    next = tn;
+    transitive();
+    return merge();
+}
+
+void TypeDArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+    //printf("TypeDArray::resolve() %s\n", toChars());
+    next->resolve(loc, sc, pe, pt, ps, intypeid);
+    //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
+    if (*pe)
+    {
+        // It's really a slice expression
+        if (Dsymbol *s = getDsymbol(*pe))
+            *pe = new DsymbolExp(loc, s);
+        *pe = new ArrayExp(loc, *pe);
+    }
+    else if (*ps)
+    {
+        TupleDeclaration *td = (*ps)->isTupleDeclaration();
+        if (td)
+            ;   // keep *ps
+        else
+            goto Ldefault;
+    }
+    else
+    {
+        if ((*pt)->ty != Terror)
+            next = *pt;     // prevent re-running semantic() on 'next'
+     Ldefault:
+        Type::resolve(loc, sc, pe, pt, ps, intypeid);
+    }
+}
+
+Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+#if LOGDOTEXP
+    printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (e->op == TOKtype &&
+        (ident == Id::length || ident == Id::ptr))
+    {
+        e->error("%s is not an expression", e->toChars());
+        return new ErrorExp();
+    }
+    if (ident == Id::length)
+    {
+        if (e->op == TOKstring)
+        {
+            StringExp *se = (StringExp *)e;
+            return new IntegerExp(se->loc, se->len, Type::tsize_t);
+        }
+        if (e->op == TOKnull)
+            return new IntegerExp(e->loc, 0, Type::tsize_t);
+        e = new ArrayLengthExp(e->loc, e);
+        e->type = Type::tsize_t;
+        return e;
+    }
+    else if (ident == Id::ptr)
+    {
+        e = e->castTo(sc, next->pointerTo());
+        return e;
+    }
+    else
+    {
+        e = TypeArray::dotExp(sc, e, ident, flag);
+    }
+    return e;
+}
+
+bool TypeDArray::isString()
+{
+    TY nty = next->toBasetype()->ty;
+    return nty == Tchar || nty == Twchar || nty == Tdchar;
+}
+
+MATCH TypeDArray::implicitConvTo(Type *to)
+{
+    //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
+    if (equals(to))
+        return MATCHexact;
+
+    if (to->ty == Tarray)
+    {
+        TypeDArray *ta = (TypeDArray *)to;
+
+        if (!MODimplicitConv(next->mod, ta->next->mod))
+            return MATCHnomatch;        // not const-compatible
+
+        /* Allow conversion to void[]
+         */
+        if (next->ty != Tvoid && ta->next->ty == Tvoid)
+        {
+            return MATCHconvert;
+        }
+
+        MATCH m = next->constConv(ta->next);
+        if (m > MATCHnomatch)
+        {
+            if (m == MATCHexact && mod != to->mod)
+                m = MATCHconst;
+            return m;
+        }
+    }
+    return Type::implicitConvTo(to);
+}
+
+Expression *TypeDArray::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeDArray::defaultInit() '%s'\n", toChars());
+#endif
+    return new NullExp(loc, this);
+}
+
+bool TypeDArray::isZeroInit(Loc loc)
+{
+    return true;
+}
+
+bool TypeDArray::isBoolean()
+{
+    return true;
+}
+
+bool TypeDArray::hasPointers()
+{
+    return true;
+}
+
+
+/***************************** TypeAArray *****************************/
+
+TypeAArray::TypeAArray(Type *t, Type *index)
+    : TypeArray(Taarray, t)
+{
+    this->index = index;
+    this->loc = Loc();
+    this->sc = NULL;
+}
+
+TypeAArray *TypeAArray::create(Type *t, Type *index)
+{
+    return new TypeAArray(t, index);
+}
+
+const char *TypeAArray::kind()
+{
+    return "aarray";
+}
+
+Type *TypeAArray::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    Type *ti = index->syntaxCopy();
+    if (t == next && ti == index)
+        t = this;
+    else
+    {
+        t = new TypeAArray(t, ti);
+        t->mod = mod;
+    }
+    return t;
+}
+
+d_uns64 TypeAArray::size(Loc loc)
+{
+    return Target::ptrsize;
+}
+
+Type *TypeAArray::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeAArray::semantic() %s index->ty = %d\n", toChars(), index->ty);
+    if (deco)
+        return this;
+
+    this->loc = loc;
+    this->sc = sc;
+    if (sc)
+        sc->setNoFree();
+
+    // Deal with the case where we thought the index was a type, but
+    // in reality it was an expression.
+    if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray ||
+        index->ty == Ttypeof || index->ty == Treturn)
+    {
+        Expression *e;
+        Type *t;
+        Dsymbol *s;
+
+        index->resolve(loc, sc, &e, &t, &s);
+        if (e)
+        {
+            // It was an expression -
+            // Rewrite as a static array
+            TypeSArray *tsa = new TypeSArray(next, e);
+            return tsa->semantic(loc, sc);
+        }
+        else if (t)
+            index = t->semantic(loc, sc);
+        else
+        {
+            index->error(loc, "index is not a type or an expression");
+            return Type::terror;
+        }
+    }
+    else
+        index = index->semantic(loc,sc);
+    index = index->merge2();
+
+    if (index->nextOf() && !index->nextOf()->isImmutable())
+    {
+        index = index->constOf()->mutableOf();
+#if 0
+printf("index is %p %s\n", index, index->toChars());
+index->check();
+printf("index->mod = x%x\n", index->mod);
+printf("index->ito = x%x\n", index->ito);
+if (index->ito) {
+printf("index->ito->mod = x%x\n", index->ito->mod);
+printf("index->ito->ito = x%x\n", index->ito->ito);
+}
+#endif
+    }
+
+    switch (index->toBasetype()->ty)
+    {
+        case Tfunction:
+        case Tvoid:
+        case Tnone:
+        case Ttuple:
+            error(loc, "can't have associative array key of %s", index->toBasetype()->toChars());
+        case Terror:
+            return Type::terror;
+        default:
+            break;
+    }
+    Type *tbase = index->baseElemOf();
+    while (tbase->ty == Tarray)
+        tbase = tbase->nextOf()->baseElemOf();
+    if (tbase->ty == Tstruct)
+    {
+        /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
+         */
+        StructDeclaration *sd = ((TypeStruct *)tbase)->sym;
+        if (sd->_scope)
+            sd->semantic(NULL);
+
+        // duplicate a part of StructDeclaration::semanticTypeInfoMembers
+        //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd->xeq, sd->xerreq, sd->xhash);
+        if (sd->xeq &&
+            sd->xeq->_scope &&
+            sd->xeq->semanticRun < PASSsemantic3done)
+        {
+            unsigned errors = global.startGagging();
+            sd->xeq->semantic3(sd->xeq->_scope);
+            if (global.endGagging(errors))
+                sd->xeq = sd->xerreq;
+        }
+
+        const char *s = (index->toBasetype()->ty != Tstruct) ? "bottom of " : "";
+        if (!sd->xeq)
+        {
+            // If sd->xhash != NULL:
+            //   sd or its fields have user-defined toHash.
+            //   AA assumes that its result is consistent with bitwise equality.
+            // else:
+            //   bitwise equality & hashing
+        }
+        else if (sd->xeq == sd->xerreq)
+        {
+            if (search_function(sd, Id::eq))
+            {
+                error(loc, "%sAA key type %s does not have 'bool opEquals(ref const %s) const'",
+                        s, sd->toChars(), sd->toChars());
+            }
+            else
+            {
+                error(loc, "%sAA key type %s does not support const equality",
+                        s, sd->toChars());
+            }
+            return Type::terror;
+        }
+        else if (!sd->xhash)
+        {
+            if (search_function(sd, Id::eq))
+            {
+                error(loc, "%sAA key type %s should have 'size_t toHash() const nothrow @safe' if opEquals defined",
+                        s, sd->toChars());
+            }
+            else
+            {
+                error(loc, "%sAA key type %s supports const equality but doesn't support const hashing",
+                        s, sd->toChars());
+            }
+            return Type::terror;
+        }
+        else
+        {
+            // defined equality & hashing
+            assert(sd->xeq && sd->xhash);
+
+            /* xeq and xhash may be implicitly defined by compiler. For example:
+             *   struct S { int[] arr; }
+             * With 'arr' field equality and hashing, compiler will implicitly
+             * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
+             */
+        }
+    }
+    else if (tbase->ty == Tclass && !((TypeClass *)tbase)->sym->isInterfaceDeclaration())
+    {
+        ClassDeclaration *cd = ((TypeClass *)tbase)->sym;
+        if (cd->_scope)
+            cd->semantic(NULL);
+
+        if (!ClassDeclaration::object)
+        {
+            error(Loc(), "missing or corrupt object.d");
+            fatal();
+        }
+
+        static FuncDeclaration *feq   = NULL;
+        static FuncDeclaration *fcmp  = NULL;
+        static FuncDeclaration *fhash = NULL;
+        if (!feq)   feq   = search_function(ClassDeclaration::object, Id::eq)->isFuncDeclaration();
+        if (!fcmp)  fcmp  = search_function(ClassDeclaration::object, Id::cmp)->isFuncDeclaration();
+        if (!fhash) fhash = search_function(ClassDeclaration::object, Id::tohash)->isFuncDeclaration();
+        assert(fcmp && feq && fhash);
+
+        if (feq ->vtblIndex < cd->vtbl.dim && cd->vtbl[feq ->vtblIndex] == feq)
+        {
+        #if 1
+            if (fcmp->vtblIndex < cd->vtbl.dim && cd->vtbl[fcmp->vtblIndex] != fcmp)
+            {
+                const char *s = (index->toBasetype()->ty != Tclass) ? "bottom of " : "";
+                error(loc, "%sAA key type %s now requires equality rather than comparison",
+                    s, cd->toChars());
+                errorSupplemental(loc, "Please override Object.opEquals and toHash.");
+            }
+        #endif
+        }
+    }
+    next = next->semantic(loc,sc)->merge2();
+    transitive();
+
+    switch (next->toBasetype()->ty)
+    {
+        case Tfunction:
+        case Tvoid:
+        case Tnone:
+        case Ttuple:
+            error(loc, "can't have associative array of %s", next->toChars());
+        case Terror:
+            return Type::terror;
+    }
+    if (next->isscope())
+    {   error(loc, "cannot have array of scope %s", next->toChars());
+        return Type::terror;
+    }
+    return merge();
+}
+
+void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+    //printf("TypeAArray::resolve() %s\n", toChars());
+
+    // Deal with the case where we thought the index was a type, but
+    // in reality it was an expression.
+    if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray)
+    {
+        Expression *e;
+        Type *t;
+        Dsymbol *s;
+
+        index->resolve(loc, sc, &e, &t, &s, intypeid);
+        if (e)
+        {
+            // It was an expression -
+            // Rewrite as a static array
+            TypeSArray *tsa = new TypeSArray(next, e);
+            tsa->mod = this->mod;   // just copy mod field so tsa's semantic is not yet done
+            return tsa->resolve(loc, sc, pe, pt, ps, intypeid);
+        }
+        else if (t)
+            index = t;
+        else
+            index->error(loc, "index is not a type or an expression");
+    }
+    Type::resolve(loc, sc, pe, pt, ps, intypeid);
+}
+
+
+Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+#if LOGDOTEXP
+    printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::length)
+    {
+        static FuncDeclaration *fd_aaLen = NULL;
+        if (fd_aaLen == NULL)
+        {
+            Parameters *fparams = new Parameters();
+            fparams->push(new Parameter(STCin, this, NULL, NULL));
+            fd_aaLen = FuncDeclaration::genCfunc(fparams, Type::tsize_t, Id::aaLen);
+            TypeFunction *tf = (TypeFunction *)fd_aaLen->type;
+            tf->purity = PUREconst;
+            tf->isnothrow = true;
+            tf->isnogc = false;
+        }
+        Expression *ev = new VarExp(e->loc, fd_aaLen, false);
+        e = new CallExp(e->loc, ev, e);
+        e->type = ((TypeFunction *)fd_aaLen->type)->next;
+    }
+    else
+        e = Type::dotExp(sc, e, ident, flag);
+    return e;
+}
+
+Expression *TypeAArray::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeAArray::defaultInit() '%s'\n", toChars());
+#endif
+    return new NullExp(loc, this);
+}
+
+bool TypeAArray::isZeroInit(Loc loc)
+{
+    return true;
+}
+
+bool TypeAArray::isBoolean()
+{
+    return true;
+}
+
+bool TypeAArray::hasPointers()
+{
+    return true;
+}
+
+MATCH TypeAArray::implicitConvTo(Type *to)
+{
+    //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
+    if (equals(to))
+        return MATCHexact;
+
+    if (to->ty == Taarray)
+    {   TypeAArray *ta = (TypeAArray *)to;
+
+        if (!MODimplicitConv(next->mod, ta->next->mod))
+            return MATCHnomatch;        // not const-compatible
+
+        if (!MODimplicitConv(index->mod, ta->index->mod))
+            return MATCHnomatch;        // not const-compatible
+
+        MATCH m = next->constConv(ta->next);
+        MATCH mi = index->constConv(ta->index);
+        if (m > MATCHnomatch && mi > MATCHnomatch)
+        {
+            return MODimplicitConv(mod, to->mod) ? MATCHconst : MATCHnomatch;
+        }
+    }
+    return Type::implicitConvTo(to);
+}
+
+MATCH TypeAArray::constConv(Type *to)
+{
+    if (to->ty == Taarray)
+    {
+        TypeAArray *taa = (TypeAArray *)to;
+        MATCH mindex = index->constConv(taa->index);
+        MATCH mkey = next->constConv(taa->next);
+        // Pick the worst match
+        return mkey < mindex ? mkey : mindex;
+    }
+    return Type::constConv(to);
+}
+
+/***************************** TypePointer *****************************/
+
+TypePointer::TypePointer(Type *t)
+    : TypeNext(Tpointer, t)
+{
+}
+
+TypePointer *TypePointer::create(Type *t)
+{
+    return new TypePointer(t);
+}
+
+const char *TypePointer::kind()
+{
+    return "pointer";
+}
+
+Type *TypePointer::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    if (t == next)
+        t = this;
+    else
+    {
+        t = new TypePointer(t);
+        t->mod = mod;
+    }
+    return t;
+}
+
+Type *TypePointer::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypePointer::semantic() %s\n", toChars());
+    if (deco)
+        return this;
+    Type *n = next->semantic(loc, sc);
+    switch (n->toBasetype()->ty)
+    {
+        case Ttuple:
+            error(loc, "can't have pointer to %s", n->toChars());
+        case Terror:
+            return Type::terror;
+        default:
+            break;
+    }
+    if (n != next)
+    {
+        deco = NULL;
+    }
+    next = n;
+    if (next->ty != Tfunction)
+    {   transitive();
+        return merge();
+    }
+#if 0
+    return merge();
+#else
+    deco = merge()->deco;
+    /* Don't return merge(), because arg identifiers and default args
+     * can be different
+     * even though the types match
+     */
+    return this;
+#endif
+}
+
+
+d_uns64 TypePointer::size(Loc loc)
+{
+    return Target::ptrsize;
+}
+
+MATCH TypePointer::implicitConvTo(Type *to)
+{
+    //printf("TypePointer::implicitConvTo(to = %s) %s\n", to->toChars(), toChars());
+
+    if (equals(to))
+        return MATCHexact;
+    if (next->ty == Tfunction)
+    {
+        if (to->ty == Tpointer)
+        {
+            TypePointer *tp = (TypePointer *)to;
+            if (tp->next->ty == Tfunction)
+            {
+                if (next->equals(tp->next))
+                    return MATCHconst;
+
+                if (next->covariant(tp->next) == 1)
+                {
+                    Type *tret = this->next->nextOf();
+                    Type *toret = tp->next->nextOf();
+                    if (tret->ty == Tclass && toret->ty == Tclass)
+                    {
+                        /* Bugzilla 10219: Check covariant interface return with offset tweaking.
+                         * interface I {}
+                         * class C : Object, I {}
+                         * I function() dg = function C() {}    // should be error
+                         */
+                        int offset = 0;
+                        if (toret->isBaseOf(tret, &offset) && offset != 0)
+                            return MATCHnomatch;
+                    }
+                    return MATCHconvert;
+                }
+            }
+            else if (tp->next->ty == Tvoid)
+            {
+                // Allow conversions to void*
+                return MATCHconvert;
+            }
+        }
+        return MATCHnomatch;
+    }
+    else if (to->ty == Tpointer)
+    {
+        TypePointer *tp = (TypePointer *)to;
+        assert(tp->next);
+
+        if (!MODimplicitConv(next->mod, tp->next->mod))
+            return MATCHnomatch;        // not const-compatible
+
+        /* Alloc conversion to void*
+         */
+        if (next->ty != Tvoid && tp->next->ty == Tvoid)
+        {
+            return MATCHconvert;
+        }
+
+        MATCH m = next->constConv(tp->next);
+        if (m > MATCHnomatch)
+        {
+            if (m == MATCHexact && mod != to->mod)
+                m = MATCHconst;
+            return m;
+        }
+    }
+    return MATCHnomatch;
+}
+
+MATCH TypePointer::constConv(Type *to)
+{
+    if (next->ty == Tfunction)
+    {
+        if (to->nextOf() && next->equals(((TypeNext *)to)->next))
+            return Type::constConv(to);
+        else
+            return MATCHnomatch;
+    }
+    return TypeNext::constConv(to);
+}
+
+bool TypePointer::isscalar()
+{
+    return true;
+}
+
+Expression *TypePointer::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypePointer::defaultInit() '%s'\n", toChars());
+#endif
+    return new NullExp(loc, this);
+}
+
+bool TypePointer::isZeroInit(Loc loc)
+{
+    return true;
+}
+
+bool TypePointer::hasPointers()
+{
+    return true;
+}
+
+
+/***************************** TypeReference *****************************/
+
+TypeReference::TypeReference(Type *t)
+    : TypeNext(Treference, t)
+{
+    // BUG: what about references to static arrays?
+}
+
+const char *TypeReference::kind()
+{
+    return "reference";
+}
+
+Type *TypeReference::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    if (t == next)
+        t = this;
+    else
+    {
+        t = new TypeReference(t);
+        t->mod = mod;
+    }
+    return t;
+}
+
+Type *TypeReference::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeReference::semantic()\n");
+    Type *n = next->semantic(loc, sc);
+    if (n != next)
+        deco = NULL;
+    next = n;
+    transitive();
+    return merge();
+}
+
+
+d_uns64 TypeReference::size(Loc loc)
+{
+    return Target::ptrsize;
+}
+
+Expression *TypeReference::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+#if LOGDOTEXP
+    printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+
+    // References just forward things along
+    return next->dotExp(sc, e, ident, flag);
+}
+
+Expression *TypeReference::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeReference::defaultInit() '%s'\n", toChars());
+#endif
+    return new NullExp(loc, this);
+}
+
+bool TypeReference::isZeroInit(Loc loc)
+{
+    return true;
+}
+
+
+/***************************** TypeFunction *****************************/
+
+TypeFunction::TypeFunction(Parameters *parameters, Type *treturn, int varargs, LINK linkage, StorageClass stc)
+    : TypeNext(Tfunction, treturn)
+{
+//if (!treturn) *(char*)0=0;
+//    assert(treturn);
+    assert(0 <= varargs && varargs <= 2);
+    this->parameters = parameters;
+    this->varargs = varargs;
+    this->linkage = linkage;
+    this->inuse = 0;
+    this->isnothrow = false;
+    this->isnogc = false;
+    this->purity = PUREimpure;
+    this->isproperty = false;
+    this->isref = false;
+    this->isreturn = false;
+    this->isscope = false;
+    this->isscopeinferred = false;
+    this->iswild = 0;
+    this->fargs = NULL;
+
+    if (stc & STCpure)
+        this->purity = PUREfwdref;
+    if (stc & STCnothrow)
+        this->isnothrow = true;
+    if (stc & STCnogc)
+        this->isnogc = true;
+    if (stc & STCproperty)
+        this->isproperty = true;
+
+    if (stc & STCref)
+        this->isref = true;
+    if (stc & STCreturn)
+        this->isreturn = true;
+    if (stc & STCscope)
+        this->isscope = true;
+    if (stc & STCscopeinferred)
+        this->isscopeinferred = true;
+
+    this->trust = TRUSTdefault;
+    if (stc & STCsafe)
+        this->trust = TRUSTsafe;
+    if (stc & STCsystem)
+        this->trust = TRUSTsystem;
+    if (stc & STCtrusted)
+        this->trust = TRUSTtrusted;
+}
+
+TypeFunction *TypeFunction::create(Parameters *parameters, Type *treturn, int varargs, LINK linkage, StorageClass stc)
+{
+    return new TypeFunction(parameters, treturn, varargs, linkage, stc);
+}
+
+const char *TypeFunction::kind()
+{
+    return "function";
+}
+
+Type *TypeFunction::syntaxCopy()
+{
+    Type *treturn = next ? next->syntaxCopy() : NULL;
+    Parameters *params = Parameter::arraySyntaxCopy(parameters);
+    TypeFunction *t = new TypeFunction(params, treturn, varargs, linkage);
+    t->mod = mod;
+    t->isnothrow = isnothrow;
+    t->isnogc = isnogc;
+    t->purity = purity;
+    t->isproperty = isproperty;
+    t->isref = isref;
+    t->isreturn = isreturn;
+    t->isscope = isscope;
+    t->isscopeinferred = isscopeinferred;
+    t->iswild = iswild;
+    t->trust = trust;
+    t->fargs = fargs;
+    return t;
+}
+
+/*******************************
+ * Covariant means that 'this' can substitute for 't',
+ * i.e. a pure function is a match for an impure type.
+ * Params:
+ *      t = type 'this' is covariant with
+ *      pstc = if not null, store STCxxxx which would make it covariant
+ *      fix17349 = enable fix https://issues.dlang.org/show_bug.cgi?id=17349
+ * Returns:
+ *      0       types are distinct
+ *      1       this is covariant with t
+ *      2       arguments match as far as overloading goes,
+ *              but types are not covariant
+ *      3       cannot determine covariance because of forward references
+ *      *pstc   STCxxxx which would make it covariant
+ */
+
+int Type::covariant(Type *t, StorageClass *pstc, bool fix17349)
+{
+#if 0
+    printf("Type::covariant(t = %s) %s\n", t->toChars(), toChars());
+    printf("deco = %p, %p\n", deco, t->deco);
+//    printf("ty = %d\n", next->ty);
+    printf("mod = %x, %x\n", mod, t->mod);
+#endif
+
+    if (pstc)
+        *pstc = 0;
+    StorageClass stc = 0;
+
+    bool notcovariant = false;
+
+    TypeFunction *t1;
+    TypeFunction *t2;
+
+    if (equals(t))
+        return 1;                       // covariant
+
+    if (ty != Tfunction || t->ty != Tfunction)
+        goto Ldistinct;
+
+    t1 = (TypeFunction *)this;
+    t2 = (TypeFunction *)t;
+
+    if (t1->varargs != t2->varargs)
+        goto Ldistinct;
+
+    if (t1->parameters && t2->parameters)
+    {
+        size_t dim = Parameter::dim(t1->parameters);
+        if (dim != Parameter::dim(t2->parameters))
+            goto Ldistinct;
+
+        for (size_t i = 0; i < dim; i++)
+        {
+            Parameter *fparam1 = Parameter::getNth(t1->parameters, i);
+            Parameter *fparam2 = Parameter::getNth(t2->parameters, i);
+
+            if (!fparam1->type->equals(fparam2->type))
+            {
+                if (!fix17349)
+                    goto Ldistinct;
+                Type *tp1 = fparam1->type;
+                Type *tp2 = fparam2->type;
+                if (tp1->ty == tp2->ty)
+                {
+                    if (tp1->ty == Tclass)
+                    {
+                        if (((TypeClass *)tp1)->sym == ((TypeClass *)tp2)->sym && MODimplicitConv(tp2->mod, tp1->mod))
+                            goto Lcov;
+                    }
+                    else if (tp1->ty == Tstruct)
+                    {
+                        if (((TypeStruct *)tp1)->sym == ((TypeStruct *)tp2)->sym && MODimplicitConv(tp2->mod, tp1->mod))
+                            goto Lcov;
+                    }
+                    else if (tp1->ty == Tpointer)
+                    {
+                        if (tp2->implicitConvTo(tp1))
+                            goto Lcov;
+                    }
+                    else if (tp1->ty == Tarray)
+                    {
+                        if (tp2->implicitConvTo(tp1))
+                            goto Lcov;
+                    }
+                    else if (tp1->ty == Tdelegate)
+                    {
+                        if (tp1->implicitConvTo(tp2))
+                            goto Lcov;
+                    }
+                }
+                goto Ldistinct;
+            }
+        Lcov:
+            notcovariant |= !fparam1->isCovariant(t1->isref, fparam2);
+        }
+    }
+    else if (t1->parameters != t2->parameters)
+    {
+        size_t dim1 = !t1->parameters ? 0 : t1->parameters->dim;
+        size_t dim2 = !t2->parameters ? 0 : t2->parameters->dim;
+        if (dim1 || dim2)
+            goto Ldistinct;
+    }
+
+    // The argument lists match
+    if (notcovariant)
+        goto Lnotcovariant;
+    if (t1->linkage != t2->linkage)
+        goto Lnotcovariant;
+
+  {
+    // Return types
+    Type *t1n = t1->next;
+    Type *t2n = t2->next;
+
+    if (!t1n || !t2n)           // happens with return type inference
+        goto Lnotcovariant;
+
+    if (t1n->equals(t2n))
+        goto Lcovariant;
+    if (t1n->ty == Tclass && t2n->ty == Tclass)
+    {
+        /* If same class type, but t2n is const, then it's
+         * covariant. Do this test first because it can work on
+         * forward references.
+         */
+        if (((TypeClass *)t1n)->sym == ((TypeClass *)t2n)->sym &&
+            MODimplicitConv(t1n->mod, t2n->mod))
+            goto Lcovariant;
+
+        // If t1n is forward referenced:
+        ClassDeclaration *cd = ((TypeClass *)t1n)->sym;
+        if (cd->_scope)
+            cd->semantic(NULL);
+        if (!cd->isBaseInfoComplete())
+        {
+            return 3;   // forward references
+        }
+    }
+    if (t1n->ty == Tstruct && t2n->ty == Tstruct)
+    {
+        if (((TypeStruct *)t1n)->sym == ((TypeStruct *)t2n)->sym &&
+            MODimplicitConv(t1n->mod, t2n->mod))
+            goto Lcovariant;
+    }
+    else if (t1n->ty == t2n->ty && t1n->implicitConvTo(t2n))
+        goto Lcovariant;
+    else if (t1n->ty == Tnull && t1n->implicitConvTo(t2n) &&
+             t1n->size() == t2n->size())
+        goto Lcovariant;
+  }
+    goto Lnotcovariant;
+
+Lcovariant:
+    if (t1->isref != t2->isref)
+        goto Lnotcovariant;
+
+    if (!t1->isref && (t1->isscope || t2->isscope))
+    {
+        StorageClass stc1 = t1->isscope ? STCscope : 0;
+        StorageClass stc2 = t2->isscope ? STCscope : 0;
+        if (t1->isreturn)
+        {
+            stc1 |= STCreturn;
+            if (!t1->isscope)
+                stc1 |= STCref;
+        }
+        if (t2->isreturn)
+        {
+            stc2 |= STCreturn;
+            if (!t2->isscope)
+                stc2 |= STCref;
+        }
+        if (!Parameter::isCovariantScope(t1->isref, stc1, stc2))
+            goto Lnotcovariant;
+    }
+
+    // We can subtract 'return' from 'this', but cannot add it
+    else if (t1->isreturn && !t2->isreturn)
+        goto Lnotcovariant;
+
+    /* Can convert mutable to const
+     */
+    if (!MODimplicitConv(t2->mod, t1->mod))
+    {
+#if 0//stop attribute inference with const
+        // If adding 'const' will make it covariant
+        if (MODimplicitConv(t2->mod, MODmerge(t1->mod, MODconst)))
+            stc |= STCconst;
+        else
+            goto Lnotcovariant;
+#else
+        goto Ldistinct;
+#endif
+    }
+
+    /* Can convert pure to impure, nothrow to throw, and nogc to gc
+     */
+    if (!t1->purity && t2->purity)
+        stc |= STCpure;
+
+    if (!t1->isnothrow && t2->isnothrow)
+        stc |= STCnothrow;
+
+    if (!t1->isnogc && t2->isnogc)
+        stc |= STCnogc;
+
+    /* Can convert safe/trusted to system
+     */
+    if (t1->trust <= TRUSTsystem && t2->trust >= TRUSTtrusted)
+    {
+        // Should we infer trusted or safe? Go with safe.
+        stc |= STCsafe;
+    }
+
+    if (stc)
+    {   if (pstc)
+            *pstc = stc;
+        goto Lnotcovariant;
+    }
+
+    //printf("\tcovaraint: 1\n");
+    return 1;
+
+Ldistinct:
+    //printf("\tcovaraint: 0\n");
+    return 0;
+
+Lnotcovariant:
+    //printf("\tcovaraint: 2\n");
+    return 2;
+}
+
+Type *TypeFunction::semantic(Loc loc, Scope *sc)
+{
+    if (deco)                   // if semantic() already run
+    {
+        //printf("already done\n");
+        return this;
+    }
+    //printf("TypeFunction::semantic() this = %p\n", this);
+    //printf("TypeFunction::semantic() %s, sc->stc = %llx, fargs = %p\n", toChars(), sc->stc, fargs);
+
+    bool errors = false;
+
+    /* Copy in order to not mess up original.
+     * This can produce redundant copies if inferring return type,
+     * as semantic() will get called again on this.
+     */
+    TypeFunction *tf = (TypeFunction *)copy();
+    if (parameters)
+    {
+        tf->parameters = parameters->copy();
+        for (size_t i = 0; i < parameters->dim; i++)
+        {
+            Parameter *p = (Parameter *)mem.xmalloc(sizeof(Parameter));
+            memcpy((void *)p, (void *)(*parameters)[i], sizeof(Parameter));
+            (*tf->parameters)[i] = p;
+        }
+    }
+
+    if (sc->stc & STCpure)
+        tf->purity = PUREfwdref;
+    if (sc->stc & STCnothrow)
+        tf->isnothrow = true;
+    if (sc->stc & STCnogc)
+        tf->isnogc = true;
+    if (sc->stc & STCref)
+        tf->isref = true;
+    if (sc->stc & STCreturn)
+        tf->isreturn = true;
+    if (sc->stc & STCscope)
+        tf->isscope = true;
+    if (sc->stc & STCscopeinferred)
+        tf->isscopeinferred = true;
+
+//    if ((sc->stc & (STCreturn | STCref)) == STCreturn)
+//        tf->isscope = true;                                 // return by itself means 'return scope'
+
+    if (tf->trust == TRUSTdefault)
+    {
+        if (sc->stc & STCsafe)
+            tf->trust = TRUSTsafe;
+        if (sc->stc & STCsystem)
+            tf->trust = TRUSTsystem;
+        if (sc->stc & STCtrusted)
+            tf->trust = TRUSTtrusted;
+    }
+
+    if (sc->stc & STCproperty)
+        tf->isproperty = true;
+
+    tf->linkage = sc->linkage;
+#if 0
+    /* If the parent is @safe, then this function defaults to safe
+     * too.
+     * If the parent's @safe-ty is inferred, then this function's @safe-ty needs
+     * to be inferred first.
+     */
+    if (tf->trust == TRUSTdefault)
+        for (Dsymbol *p = sc->func; p; p = p->toParent2())
+        {   FuncDeclaration *fd = p->isFuncDeclaration();
+            if (fd)
+            {
+                if (fd->isSafeBypassingInference())
+                    tf->trust = TRUSTsafe;              // default to @safe
+                break;
+            }
+        }
+#endif
+    bool wildreturn = false;
+    if (tf->next)
+    {
+        sc = sc->push();
+        sc->stc &= ~(STC_TYPECTOR | STC_FUNCATTR);
+        tf->next = tf->next->semantic(loc, sc);
+        sc = sc->pop();
+        errors |= tf->checkRetType(loc);
+        if (tf->next->isscope() && !(sc->flags & SCOPEctor))
+        {
+            error(loc, "functions cannot return scope %s", tf->next->toChars());
+            errors = true;
+        }
+        if (tf->next->hasWild())
+            wildreturn = true;
+
+        if (tf->isreturn && !tf->isref && !tf->next->hasPointers())
+        {
+            error(loc, "function type '%s' has 'return' but does not return any indirections", tf->toChars());
+        }
+    }
+
+    unsigned char wildparams = 0;
+    if (tf->parameters)
+    {
+        /* Create a scope for evaluating the default arguments for the parameters
+         */
+        Scope *argsc = sc->push();
+        argsc->stc = 0;                 // don't inherit storage class
+        argsc->protection = Prot(PROTpublic);
+        argsc->func = NULL;
+
+        size_t dim = Parameter::dim(tf->parameters);
+        for (size_t i = 0; i < dim; i++)
+        {
+            Parameter *fparam = Parameter::getNth(tf->parameters, i);
+            tf->inuse++;
+            fparam->type = fparam->type->semantic(loc, argsc);
+            if (tf->inuse == 1) tf->inuse--;
+
+            if (fparam->type->ty == Terror)
+            {
+                errors = true;
+                continue;
+            }
+
+            fparam->type = fparam->type->addStorageClass(fparam->storageClass);
+
+            if (fparam->storageClass & (STCauto | STCalias | STCstatic))
+            {
+                if (!fparam->type)
+                    continue;
+            }
+
+            Type *t = fparam->type->toBasetype();
+
+            if (t->ty == Tfunction)
+            {
+                error(loc, "cannot have parameter of function type %s", fparam->type->toChars());
+                errors = true;
+            }
+            else if (!(fparam->storageClass & (STCref | STCout)) &&
+                     (t->ty == Tstruct || t->ty == Tsarray || t->ty == Tenum))
+            {
+                Type *tb2 = t->baseElemOf();
+                if (tb2->ty == Tstruct && !((TypeStruct *)tb2)->sym->members ||
+                    tb2->ty == Tenum && !((TypeEnum *)tb2)->sym->memtype)
+                {
+                    error(loc, "cannot have parameter of opaque type %s by value", fparam->type->toChars());
+                    errors = true;
+                }
+            }
+            else if (!(fparam->storageClass & STClazy) && t->ty == Tvoid)
+            {
+                error(loc, "cannot have parameter of type %s", fparam->type->toChars());
+                errors = true;
+            }
+
+            if ((fparam->storageClass & (STCref | STCwild)) == (STCref | STCwild))
+            {
+                // 'ref inout' implies 'return'
+                fparam->storageClass |= STCreturn;
+            }
+
+            if (fparam->storageClass & STCreturn)
+            {
+                if (fparam->storageClass & (STCref | STCout))
+                {
+                    // Disabled for the moment awaiting improvement to allow return by ref
+                    // to be transformed into return by scope.
+                    if (0 && !tf->isref)
+                    {
+                        StorageClass stc = fparam->storageClass & (STCref | STCout);
+                        error(loc, "parameter %s is 'return %s' but function does not return by ref",
+                            fparam->ident ? fparam->ident->toChars() : "",
+                            stcToChars(stc));
+                        errors = true;
+                    }
+                }
+                else
+                {
+                    fparam->storageClass |= STCscope;        // 'return' implies 'scope'
+                    if (tf->isref)
+                    {
+                    }
+                    else if (!tf->isref && tf->next && !tf->next->hasPointers())
+                    {
+                        error(loc, "parameter %s is 'return' but function does not return any indirections",
+                            fparam->ident ? fparam->ident->toChars() : "");
+                        errors = true;
+                    }
+                }
+            }
+
+            if (fparam->storageClass & (STCref | STClazy))
+            {
+            }
+            else if (fparam->storageClass & STCout)
+            {
+                if (unsigned char m = fparam->type->mod & (MODimmutable | MODconst | MODwild))
+                {
+                    error(loc, "cannot have %s out parameter of type %s", MODtoChars(m), t->toChars());
+                    errors = true;
+                }
+                else
+                {
+                    Type *tv = t;
+                    while (tv->ty == Tsarray)
+                        tv = tv->nextOf()->toBasetype();
+                    if (tv->ty == Tstruct && ((TypeStruct *)tv)->sym->noDefaultCtor)
+                    {
+                        error(loc, "cannot have out parameter of type %s because the default construction is disabled",
+                            fparam->type->toChars());
+                        errors = true;
+                    }
+                }
+            }
+
+            if (fparam->storageClass & STCscope && !fparam->type->hasPointers())
+            {
+                fparam->storageClass &= ~STCscope;
+                if (!(fparam->storageClass & STCref))
+                    fparam->storageClass &= ~STCreturn;
+            }
+
+            if (t->hasWild())
+            {
+                wildparams |= 1;
+                //if (tf->next && !wildreturn)
+                //    error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with 'ref')");
+            }
+
+            if (fparam->defaultArg)
+            {
+                Expression *e = fparam->defaultArg;
+                if (fparam->storageClass & (STCref | STCout))
+                {
+                    e = ::semantic(e, argsc);
+                    e = resolveProperties(argsc, e);
+                }
+                else
+                {
+                    e = inferType(e, fparam->type);
+                    Initializer *iz = new ExpInitializer(e->loc, e);
+                    iz = ::semantic(iz, argsc, fparam->type, INITnointerpret);
+                    e = initializerToExpression(iz);
+                }
+                if (e->op == TOKfunction)               // see Bugzilla 4820
+                {
+                    FuncExp *fe = (FuncExp *)e;
+                    // Replace function literal with a function symbol,
+                    // since default arg expression must be copied when used
+                    // and copying the literal itself is wrong.
+                    e = new VarExp(e->loc, fe->fd, false);
+                    e = new AddrExp(e->loc, e);
+                    e = ::semantic(e, argsc);
+                }
+                e = e->implicitCastTo(argsc, fparam->type);
+
+                // default arg must be an lvalue
+                if (fparam->storageClass & (STCout | STCref))
+                    e = e->toLvalue(argsc, e);
+
+                fparam->defaultArg = e;
+                if (e->op == TOKerror)
+                    errors = true;
+            }
+
+            /* If fparam after semantic() turns out to be a tuple, the number of parameters may
+             * change.
+             */
+            if (t->ty == Ttuple)
+            {
+                /* TypeFunction::parameter also is used as the storage of
+                 * Parameter objects for FuncDeclaration. So we should copy
+                 * the elements of TypeTuple::arguments to avoid unintended
+                 * sharing of Parameter object among other functions.
+                 */
+                TypeTuple *tt = (TypeTuple *)t;
+                if (tt->arguments && tt->arguments->dim)
+                {
+                    /* Propagate additional storage class from tuple parameters to their
+                     * element-parameters.
+                     * Make a copy, as original may be referenced elsewhere.
+                     */
+                    size_t tdim = tt->arguments->dim;
+                    Parameters *newparams = new Parameters();
+                    newparams->setDim(tdim);
+                    for (size_t j = 0; j < tdim; j++)
+                    {
+                        Parameter *narg = (*tt->arguments)[j];
+                        (*newparams)[j] = new Parameter(narg->storageClass | fparam->storageClass,
+                                narg->type, narg->ident, narg->defaultArg);
+                    }
+                    fparam->type = new TypeTuple(newparams);
+                }
+                fparam->storageClass = 0;
+
+                /* Reset number of parameters, and back up one to do this fparam again,
+                 * now that it is a tuple
+                 */
+                dim = Parameter::dim(tf->parameters);
+                i--;
+                continue;
+            }
+
+            /* Resolve "auto ref" storage class to be either ref or value,
+             * based on the argument matching the parameter
+             */
+            if (fparam->storageClass & STCauto)
+            {
+                if (fargs && i < fargs->dim && (fparam->storageClass & STCref))
+                {
+                    Expression *farg = (*fargs)[i];
+                    if (farg->isLvalue())
+                        ;                               // ref parameter
+                    else
+                        fparam->storageClass &= ~STCref;        // value parameter
+                    fparam->storageClass &= ~STCauto;    // issue 14656
+                    fparam->storageClass |= STCautoref;
+                }
+                else
+                {
+                    error(loc, "'auto' can only be used as part of 'auto ref' for template function parameters");
+                    errors = true;
+                }
+            }
+
+            // Remove redundant storage classes for type, they are already applied
+            fparam->storageClass &= ~(STC_TYPECTOR | STCin);
+        }
+        argsc->pop();
+    }
+    if (tf->isWild())
+        wildparams |= 2;
+
+    if (wildreturn && !wildparams)
+    {
+        error(loc, "inout on return means inout must be on a parameter as well for %s", toChars());
+        errors = true;
+    }
+    tf->iswild = wildparams;
+
+    if (tf->inuse)
+    {
+        error(loc, "recursive type");
+        tf->inuse = 0;
+        errors = true;
+    }
+
+    if (tf->isproperty && (tf->varargs || Parameter::dim(tf->parameters) > 2))
+    {
+        error(loc, "properties can only have zero, one, or two parameter");
+        errors = true;
+    }
+
+    if (tf->varargs == 1 && tf->linkage != LINKd && Parameter::dim(tf->parameters) == 0)
+    {
+        error(loc, "variadic functions with non-D linkage must have at least one parameter");
+        errors = true;
+    }
+
+    if (errors)
+        return terror;
+
+    if (tf->next)
+        tf->deco = tf->merge()->deco;
+
+    /* Don't return merge(), because arg identifiers and default args
+     * can be different
+     * even though the types match
+     */
+    return tf;
+}
+
+bool TypeFunction::checkRetType(Loc loc)
+{
+    Type *tb = next->toBasetype();
+    if (tb->ty == Tfunction)
+    {
+        error(loc, "functions cannot return a function");
+        next = Type::terror;
+    }
+    if (tb->ty == Ttuple)
+    {
+        error(loc, "functions cannot return a tuple");
+        next = Type::terror;
+    }
+    if (!isref && (tb->ty == Tstruct || tb->ty == Tsarray))
+    {
+        Type *tb2 = tb->baseElemOf();
+        if (tb2->ty == Tstruct && !((TypeStruct *)tb2)->sym->members)
+        {
+            error(loc, "functions cannot return opaque type %s by value", tb->toChars());
+            next = Type::terror;
+        }
+    }
+    if (tb->ty == Terror)
+        return true;
+
+    return false;
+}
+
+/********************************************
+ * Do this lazily, as the parameter types might be forward referenced.
+ */
+void TypeFunction::purityLevel()
+{
+    TypeFunction *tf = this;
+    if (tf->purity != PUREfwdref)
+        return;
+
+    /* Evaluate what kind of purity based on the modifiers for the parameters
+     */
+    tf->purity = PUREstrong;        // assume strong until something weakens it
+
+    size_t dim = Parameter::dim(tf->parameters);
+    if (!dim)
+        return;
+    for (size_t i = 0; i < dim; i++)
+    {
+        Parameter *fparam = Parameter::getNth(tf->parameters, i);
+        Type *t = fparam->type;
+        if (!t)
+            continue;
+
+        if (fparam->storageClass & (STClazy | STCout))
+        {
+            tf->purity = PUREweak;
+            break;
+        }
+        if (fparam->storageClass & STCref)
+        {
+            if (t->mod & MODimmutable)
+                continue;
+            if (t->mod & (MODconst | MODwild))
+            {
+                tf->purity = PUREconst;
+                continue;
+            }
+            tf->purity = PUREweak;
+            break;
+        }
+
+        t = t->baseElemOf();
+        if (!t->hasPointers())
+            continue;
+        if (t->mod & MODimmutable)
+            continue;
+
+        /* Accept immutable(T)[] and immutable(T)* as being strongly pure
+         */
+        if (t->ty == Tarray || t->ty == Tpointer)
+        {
+            Type *tn = t->nextOf()->toBasetype();
+            if (tn->mod & MODimmutable)
+                continue;
+            if (tn->mod & (MODconst | MODwild))
+            {
+                tf->purity = PUREconst;
+                continue;
+            }
+        }
+
+        /* The rest of this is too strict; fix later.
+         * For example, the only pointer members of a struct may be immutable,
+         * which would maintain strong purity.
+         */
+        if (t->mod & (MODconst | MODwild))
+        {
+            tf->purity = PUREconst;
+            continue;
+        }
+
+        /* Should catch delegates and function pointers, and fold in their purity
+         */
+        tf->purity = PUREweak;          // err on the side of too strict
+        break;
+    }
+}
+
+/********************************
+ * 'args' are being matched to function 'this'
+ * Determine match level.
+ * Input:
+ *      flag    1       performing a partial ordering match
+ * Returns:
+ *      MATCHxxxx
+ */
+
+MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
+{
+    //printf("TypeFunction::callMatch() %s\n", toChars());
+    MATCH match = MATCHexact;           // assume exact match
+    unsigned char wildmatch = 0;
+
+    if (tthis)
+    {
+        Type *t = tthis;
+        if (t->toBasetype()->ty == Tpointer)
+            t = t->toBasetype()->nextOf();      // change struct* to struct
+        if (t->mod != mod)
+        {
+            if (MODimplicitConv(t->mod, mod))
+                match = MATCHconst;
+            else if ((mod & MODwild)
+                && MODimplicitConv(t->mod, (mod & ~MODwild) | MODconst))
+            {
+                match = MATCHconst;
+            }
+            else
+                return MATCHnomatch;
+        }
+        if (isWild())
+        {
+            if (t->isWild())
+                wildmatch |= MODwild;
+            else if (t->isConst())
+                wildmatch |= MODconst;
+            else if (t->isImmutable())
+                wildmatch |= MODimmutable;
+            else
+                wildmatch |= MODmutable;
+        }
+    }
+
+    size_t nparams = Parameter::dim(parameters);
+    size_t nargs = args ? args->dim : 0;
+    if (nparams == nargs)
+        ;
+    else if (nargs > nparams)
+    {
+        if (varargs == 0)
+            goto Nomatch;               // too many args; no match
+        match = MATCHconvert;           // match ... with a "conversion" match level
+    }
+
+    for (size_t u = 0; u < nargs; u++)
+    {
+        if (u >= nparams)
+            break;
+        Parameter *p = Parameter::getNth(parameters, u);
+        Expression *arg = (*args)[u];
+        assert(arg);
+        Type *tprm = p->type;
+        Type *targ = arg->type;
+
+        if (!(p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid))
+        {
+            bool isRef = (p->storageClass & (STCref | STCout)) != 0;
+            wildmatch |= targ->deduceWild(tprm, isRef);
+        }
+    }
+    if (wildmatch)
+    {
+        /* Calculate wild matching modifier
+         */
+        if (wildmatch & MODconst || wildmatch & (wildmatch - 1))
+            wildmatch = MODconst;
+        else if (wildmatch & MODimmutable)
+            wildmatch = MODimmutable;
+        else if (wildmatch & MODwild)
+            wildmatch = MODwild;
+        else
+        {
+            assert(wildmatch & MODmutable);
+            wildmatch = MODmutable;
+        }
+    }
+
+    for (size_t u = 0; u < nparams; u++)
+    {
+        MATCH m;
+
+        Parameter *p = Parameter::getNth(parameters, u);
+        assert(p);
+        if (u >= nargs)
+        {
+            if (p->defaultArg)
+                continue;
+            goto L1;        // try typesafe variadics
+        }
+        {
+            Expression *arg = (*args)[u];
+            assert(arg);
+            //printf("arg: %s, type: %s\n", arg->toChars(), arg->type->toChars());
+
+            Type *targ = arg->type;
+            Type *tprm = wildmatch ? p->type->substWildTo(wildmatch) : p->type;
+
+            if (p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid)
+                m = MATCHconvert;
+            else
+            {
+                //printf("%s of type %s implicitConvTo %s\n", arg->toChars(), targ->toChars(), tprm->toChars());
+                if (flag)
+                {
+                    // for partial ordering, value is an irrelevant mockup, just look at the type
+                    m = targ->implicitConvTo(tprm);
+                }
+                else
+                    m = arg->implicitConvTo(tprm);
+                //printf("match %d\n", m);
+            }
+
+            // Non-lvalues do not match ref or out parameters
+            if (p->storageClass & (STCref | STCout))
+            {
+                // Bugzilla 13783: Don't use toBasetype() to handle enum types.
+                Type *ta = targ;
+                Type *tp = tprm;
+                //printf("fparam[%d] ta = %s, tp = %s\n", u, ta->toChars(), tp->toChars());
+
+                if (m && !arg->isLvalue())
+                {
+                    if (p->storageClass & STCout)
+                        goto Nomatch;
+
+                    if (arg->op == TOKstring && tp->ty == Tsarray)
+                    {
+                        if (ta->ty != Tsarray)
+                        {
+                            Type *tn = tp->nextOf()->castMod(ta->nextOf()->mod);
+                            dinteger_t dim = ((StringExp *)arg)->len;
+                            ta = tn->sarrayOf(dim);
+                        }
+                    }
+                    else if (arg->op == TOKslice && tp->ty == Tsarray)
+                    {
+                        // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
+                        if (ta->ty != Tsarray)
+                        {
+                            Type *tn = ta->nextOf();
+                            dinteger_t dim = ((TypeSArray *)tp)->dim->toUInteger();
+                            ta = tn->sarrayOf(dim);
+                        }
+                    }
+                    else
+                        goto Nomatch;
+                }
+
+                /* Find most derived alias this type being matched.
+                 * Bugzilla 15674: Allow on both ref and out parameters.
+                 */
+                while (1)
+                {
+                    Type *tat = ta->toBasetype()->aliasthisOf();
+                    if (!tat || !tat->implicitConvTo(tprm))
+                        break;
+                    ta = tat;
+                }
+
+                /* A ref variable should work like a head-const reference.
+                 * e.g. disallows:
+                 *  ref T      <- an lvalue of const(T) argument
+                 *  ref T[dim] <- an lvalue of const(T[dim]) argument
+                 */
+                if (!ta->constConv(tp))
+                    goto Nomatch;
+            }
+        }
+
+        /* prefer matching the element type rather than the array
+         * type when more arguments are present with T[]...
+         */
+        if (varargs == 2 && u + 1 == nparams && nargs > nparams)
+            goto L1;
+
+        //printf("\tm = %d\n", m);
+        if (m == MATCHnomatch)                  // if no match
+        {
+          L1:
+            if (varargs == 2 && u + 1 == nparams)       // if last varargs param
+            {
+                Type *tb = p->type->toBasetype();
+                TypeSArray *tsa;
+                dinteger_t sz;
+
+                switch (tb->ty)
+                {
+                    case Tsarray:
+                        tsa = (TypeSArray *)tb;
+                        sz = tsa->dim->toInteger();
+                        if (sz != nargs - u)
+                            goto Nomatch;
+                    case Tarray:
+                    {
+                        TypeArray *ta = (TypeArray *)tb;
+                        for (; u < nargs; u++)
+                        {
+                            Expression *arg = (*args)[u];
+                            assert(arg);
+
+                            /* If lazy array of delegates,
+                             * convert arg(s) to delegate(s)
+                             */
+                            Type *tret = p->isLazyArray();
+                            if (tret)
+                            {
+                                if (ta->next->equals(arg->type))
+                                    m = MATCHexact;
+                                else if (tret->toBasetype()->ty == Tvoid)
+                                    m = MATCHconvert;
+                                else
+                                {
+                                    m = arg->implicitConvTo(tret);
+                                    if (m == MATCHnomatch)
+                                        m = arg->implicitConvTo(ta->next);
+                                }
+                            }
+                            else
+                                m = arg->implicitConvTo(ta->next);
+
+                            if (m == MATCHnomatch)
+                                goto Nomatch;
+                            if (m < match)
+                                match = m;
+                        }
+                        goto Ldone;
+                    }
+                    case Tclass:
+                        // Should see if there's a constructor match?
+                        // Or just leave it ambiguous?
+                        goto Ldone;
+
+                    default:
+                        goto Nomatch;
+                }
+            }
+            goto Nomatch;
+        }
+        if (m < match)
+            match = m;                  // pick worst match
+    }
+
+Ldone:
+    //printf("match = %d\n", match);
+    return match;
+
+Nomatch:
+    //printf("no match\n");
+    return MATCHnomatch;
+}
+
+/********************************************
+ * Return true if there are lazy parameters.
+ */
+bool TypeFunction::hasLazyParameters()
+{
+    size_t dim = Parameter::dim(parameters);
+    for (size_t i = 0; i < dim; i++)
+    {
+        Parameter *fparam = Parameter::getNth(parameters, i);
+        if (fparam->storageClass & STClazy)
+            return true;
+    }
+    return false;
+}
+
+/***************************
+ * Examine function signature for parameter p and see if
+ * the value of p can 'escape' the scope of the function.
+ * This is useful to minimize the needed annotations for the parameters.
+ * Params:
+ *  p = parameter to this function
+ * Returns:
+ *  true if escapes via assignment to global or through a parameter
+ */
+
+bool TypeFunction::parameterEscapes(Parameter *p)
+{
+    /* Scope parameters do not escape.
+     * Allow 'lazy' to imply 'scope' -
+     * lazy parameters can be passed along
+     * as lazy parameters to the next function, but that isn't
+     * escaping.
+     */
+    if (parameterStorageClass(p) & (STCscope | STClazy))
+        return false;
+    return true;
+}
+
+/************************************
+ * Take the specified storage class for p,
+ * and use the function signature to infer whether
+ * STCscope and STCreturn should be OR'd in.
+ * (This will not affect the name mangling.)
+ * Params:
+ *  p = one of the parameters to 'this'
+ * Returns:
+ *  storage class with STCscope or STCreturn OR'd in
+ */
+StorageClass TypeFunction::parameterStorageClass(Parameter *p)
+{
+    StorageClass stc = p->storageClass;
+    if (!global.params.vsafe)
+        return stc;
+
+    if (stc & (STCscope | STCreturn | STClazy) || purity == PUREimpure)
+        return stc;
+
+    /* If haven't inferred the return type yet, can't infer storage classes
+     */
+    if (!nextOf())
+        return stc;
+
+    purityLevel();
+
+    // See if p can escape via any of the other parameters
+    if (purity == PUREweak)
+    {
+        const size_t dim = Parameter::dim(parameters);
+        for (size_t i = 0; i < dim; i++)
+        {
+            Parameter *fparam = Parameter::getNth(parameters, i);
+            Type *t = fparam->type;
+            if (!t)
+                continue;
+            t = t->baseElemOf();
+            if (t->isMutable() && t->hasPointers())
+            {
+                if (fparam->storageClass & (STCref | STCout))
+                {
+                }
+                else if (t->ty == Tarray || t->ty == Tpointer)
+                {
+                    Type *tn = t->nextOf()->toBasetype();
+                    if (!(tn->isMutable() && tn->hasPointers()))
+                        continue;
+                }
+                return stc;
+            }
+        }
+    }
+
+    stc |= STCscope;
+
+    Type *tret = nextOf()->toBasetype();
+    if (isref || tret->hasPointers())
+    {
+        /* The result has references, so p could be escaping
+         * that way.
+         */
+        stc |= STCreturn;
+    }
+
+    return stc;
+}
+
+Expression *TypeFunction::defaultInit(Loc loc)
+{
+    error(loc, "function does not have a default initializer");
+    return new ErrorExp();
+}
+
+Type *TypeFunction::addStorageClass(StorageClass stc)
+{
+    //printf("addStorageClass(%llx) %d\n", stc, (stc & STCscope) != 0);
+    TypeFunction *t = (TypeFunction *)Type::addStorageClass(stc);
+    if ((stc & STCpure && !t->purity) ||
+        (stc & STCnothrow && !t->isnothrow) ||
+        (stc & STCnogc && !t->isnogc) ||
+        (stc & STCscope && !t->isscope) ||
+        (stc & STCsafe && t->trust < TRUSTtrusted))
+    {
+        // Klunky to change these
+        TypeFunction *tf = new TypeFunction(t->parameters, t->next, t->varargs, t->linkage, 0);
+        tf->mod = t->mod;
+        tf->fargs = fargs;
+        tf->purity = t->purity;
+        tf->isnothrow = t->isnothrow;
+        tf->isnogc = t->isnogc;
+        tf->isproperty = t->isproperty;
+        tf->isref = t->isref;
+        tf->isreturn = t->isreturn;
+        tf->isscope = t->isscope;
+        tf->isscopeinferred = t->isscopeinferred;
+        tf->trust = t->trust;
+        tf->iswild = t->iswild;
+
+        if (stc & STCpure)
+            tf->purity = PUREfwdref;
+        if (stc & STCnothrow)
+            tf->isnothrow = true;
+        if (stc & STCnogc)
+            tf->isnogc = true;
+        if (stc & STCsafe)
+            tf->trust = TRUSTsafe;
+        if (stc & STCscope)
+        {
+            tf->isscope = true;
+            if (stc & STCscopeinferred)
+                tf->isscopeinferred = true;
+        }
+
+        tf->deco = tf->merge()->deco;
+        t = tf;
+    }
+    return t;
+}
+
+/** For each active attribute (ref/const/nogc/etc) call fp with a void* for the
+work param and a string representation of the attribute. */
+int TypeFunction::attributesApply(void *param, int (*fp)(void *, const char *), TRUSTformat trustFormat)
+{
+    int res = 0;
+
+    if (purity) res = fp(param, "pure");
+    if (res) return res;
+
+    if (isnothrow) res = fp(param, "nothrow");
+    if (res) return res;
+
+    if (isnogc) res = fp(param, "@nogc");
+    if (res) return res;
+
+    if (isproperty) res = fp(param, "@property");
+    if (res) return res;
+
+    if (isref) res = fp(param, "ref");
+    if (res) return res;
+
+    if (isreturn) res = fp(param, "return");
+    if (res) return res;
+
+    if (isscope && !isscopeinferred) res = fp(param, "scope");
+    if (res) return res;
+
+    TRUST trustAttrib = trust;
+
+    if (trustAttrib == TRUSTdefault)
+    {
+        // Print out "@system" when trust equals TRUSTdefault (if desired).
+        if (trustFormat == TRUSTformatSystem)
+            trustAttrib = TRUSTsystem;
+        else
+            return res;  // avoid calling with an empty string
+    }
+
+    return fp(param, trustToChars(trustAttrib));
+}
+
+/***************************** TypeDelegate *****************************/
+
+TypeDelegate::TypeDelegate(Type *t)
+    : TypeNext(Tfunction, t)
+{
+    ty = Tdelegate;
+}
+
+TypeDelegate *TypeDelegate::create(Type *t)
+{
+    return new TypeDelegate(t);
+}
+
+const char *TypeDelegate::kind()
+{
+    return "delegate";
+}
+
+Type *TypeDelegate::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    if (t == next)
+        t = this;
+    else
+    {
+        t = new TypeDelegate(t);
+        t->mod = mod;
+    }
+    return t;
+}
+
+Type *TypeDelegate::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeDelegate::semantic() %s\n", toChars());
+    if (deco)                   // if semantic() already run
+    {
+        //printf("already done\n");
+        return this;
+    }
+    next = next->semantic(loc,sc);
+    if (next->ty != Tfunction)
+        return terror;
+
+    /* In order to deal with Bugzilla 4028, perhaps default arguments should
+     * be removed from next before the merge.
+     */
+
+#if 0
+    return merge();
+#else
+    /* Don't return merge(), because arg identifiers and default args
+     * can be different
+     * even though the types match
+     */
+    deco = merge()->deco;
+    return this;
+#endif
+}
+
+Type *TypeDelegate::addStorageClass(StorageClass stc)
+{
+    TypeDelegate *t = (TypeDelegate*)Type::addStorageClass(stc);
+    if (!global.params.vsafe)
+        return t;
+
+    /* The rest is meant to add 'scope' to a delegate declaration if it is of the form:
+     *  alias dg_t = void* delegate();
+     *  scope dg_t dg = ...;
+     */
+    if(stc & STCscope)
+    {
+        Type *n = t->next->addStorageClass(STCscope | STCscopeinferred);
+        if (n != t->next)
+        {
+            t->next = n;
+            t->deco = t->merge()->deco; // mangling supposed to not be changed due to STCscopeinferrred
+        }
+    }
+    return t;
+}
+
+d_uns64 TypeDelegate::size(Loc loc)
+{
+    return Target::ptrsize * 2;
+}
+
+unsigned TypeDelegate::alignsize()
+{
+    return Target::ptrsize;
+}
+
+MATCH TypeDelegate::implicitConvTo(Type *to)
+{
+    //printf("TypeDelegate::implicitConvTo(this=%p, to=%p)\n", this, to);
+    //printf("from: %s\n", toChars());
+    //printf("to  : %s\n", to->toChars());
+    if (this == to)
+        return MATCHexact;
+#if 1 // not allowing covariant conversions because it interferes with overriding
+    if (to->ty == Tdelegate && this->nextOf()->covariant(to->nextOf()) == 1)
+    {
+        Type *tret = this->next->nextOf();
+        Type *toret = ((TypeDelegate *)to)->next->nextOf();
+        if (tret->ty == Tclass && toret->ty == Tclass)
+        {
+            /* Bugzilla 10219: Check covariant interface return with offset tweaking.
+             * interface I {}
+             * class C : Object, I {}
+             * I delegate() dg = delegate C() {}    // should be error
+             */
+            int offset = 0;
+            if (toret->isBaseOf(tret, &offset) && offset != 0)
+                return MATCHnomatch;
+        }
+        return MATCHconvert;
+    }
+#endif
+    return MATCHnomatch;
+}
+
+Expression *TypeDelegate::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeDelegate::defaultInit() '%s'\n", toChars());
+#endif
+    return new NullExp(loc, this);
+}
+
+bool TypeDelegate::isZeroInit(Loc loc)
+{
+    return true;
+}
+
+bool TypeDelegate::isBoolean()
+{
+    return true;
+}
+
+Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+#if LOGDOTEXP
+    printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::ptr)
+    {
+        e = new DelegatePtrExp(e->loc, e);
+        e = ::semantic(e, sc);
+    }
+    else if (ident == Id::funcptr)
+    {
+        if (!(flag & 2) && sc->func && !sc->intypeof && sc->func->setUnsafe())
+        {
+            e->error("%s.funcptr cannot be used in @safe code", e->toChars());
+            return new ErrorExp();
+        }
+        e = new DelegateFuncptrExp(e->loc, e);
+        e = ::semantic(e, sc);
+    }
+    else
+    {
+        e = Type::dotExp(sc, e, ident, flag);
+    }
+    return e;
+}
+
+bool TypeDelegate::hasPointers()
+{
+    return true;
+}
+
+
+
+/***************************** TypeQualified *****************************/
+
+TypeQualified::TypeQualified(TY ty, Loc loc)
+    : Type(ty)
+{
+    this->loc = loc;
+}
+
+void TypeQualified::syntaxCopyHelper(TypeQualified *t)
+{
+    //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t->toChars(), toChars());
+    idents.setDim(t->idents.dim);
+    for (size_t i = 0; i < idents.dim; i++)
+    {
+        RootObject *id = t->idents[i];
+        if (id->dyncast() == DYNCAST_DSYMBOL)
+        {
+            TemplateInstance *ti = (TemplateInstance *)id;
+
+            ti = (TemplateInstance *)ti->syntaxCopy(NULL);
+            id = ti;
+        }
+        else if (id->dyncast() == DYNCAST_EXPRESSION)
+        {
+            Expression *e = (Expression *)id;
+            e = e->syntaxCopy();
+            id = e;
+        }
+        else if (id->dyncast() == DYNCAST_TYPE)
+        {
+            Type *tx = (Type *)id;
+            tx = tx->syntaxCopy();
+            id = tx;
+        }
+        idents[i] = id;
+    }
+}
+
+void TypeQualified::addIdent(Identifier *ident)
+{
+    idents.push(ident);
+}
+
+void TypeQualified::addInst(TemplateInstance *inst)
+{
+    idents.push(inst);
+}
+
+void TypeQualified::addIndex(RootObject *e)
+{
+    idents.push(e);
+}
+
+d_uns64 TypeQualified::size(Loc loc)
+{
+    error(this->loc, "size of type %s is not known", toChars());
+    return SIZE_INVALID;
+}
+
+/*************************************
+ * Resolve a tuple index.
+ */
+void TypeQualified::resolveTupleIndex(Loc loc, Scope *sc, Dsymbol *s,
+        Expression **pe, Type **pt, Dsymbol **ps, RootObject *oindex)
+{
+    *pt = NULL;
+    *ps = NULL;
+    *pe = NULL;
+
+    TupleDeclaration *td = s->isTupleDeclaration();
+
+    Expression *eindex = isExpression(oindex);
+    Type *tindex = isType(oindex);
+    Dsymbol *sindex = isDsymbol(oindex);
+
+    if (!td)
+    {
+        // It's really an index expression
+        if (tindex)
+            eindex = new TypeExp(loc, tindex);
+        else if (sindex)
+            eindex = ::resolve(loc, sc, sindex, false);
+        Expression *e = new IndexExp(loc, ::resolve(loc, sc, s, false), eindex);
+        e = ::semantic(e, sc);
+        resolveExp(e, pt, pe, ps);
+        return;
+    }
+
+    // Convert oindex to Expression, then try to resolve to constant.
+    if (tindex)
+        tindex->resolve(loc, sc, &eindex, &tindex, &sindex);
+    if (sindex)
+        eindex = ::resolve(loc, sc, sindex, false);
+    if (!eindex)
+    {
+        ::error(loc, "index is %s not an expression", oindex->toChars());
+        *pt = Type::terror;
+        return;
+    }
+    sc = sc->startCTFE();
+    eindex = ::semantic(eindex, sc);
+    sc = sc->endCTFE();
+
+    eindex = eindex->ctfeInterpret();
+    if (eindex->op == TOKerror)
+    {
+        *pt = Type::terror;
+        return;
+    }
+
+    const uinteger_t d = eindex->toUInteger();
+    if (d >= td->objects->dim)
+    {
+        ::error(loc, "tuple index %llu exceeds length %u", d, td->objects->dim);
+        *pt = Type::terror;
+        return;
+    }
+
+    RootObject *o = (*td->objects)[(size_t)d];
+    *pt = isType(o);
+    *ps = isDsymbol(o);
+    *pe = isExpression(o);
+
+    if (*pt)
+        *pt = (*pt)->semantic(loc, sc);
+    if (*pe)
+        resolveExp(*pe, pt, pe, ps);
+}
+
+/*************************************
+ * Takes an array of Identifiers and figures out if
+ * it represents a Type or an Expression.
+ * Output:
+ *      if expression, *pe is set
+ *      if type, *pt is set
+ */
+void TypeQualified::resolveHelper(Loc loc, Scope *sc,
+        Dsymbol *s, Dsymbol *scopesym,
+        Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+#if 0
+    printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, toChars());
+    if (scopesym)
+        printf("\tscopesym = '%s'\n", scopesym->toChars());
+#endif
+    *pe = NULL;
+    *pt = NULL;
+    *ps = NULL;
+    if (s)
+    {
+        //printf("\t1: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
+        Declaration *d = s->isDeclaration();
+        if (d && (d->storage_class & STCtemplateparameter))
+            s = s->toAlias();
+        else
+            s->checkDeprecated(loc, sc);            // check for deprecated aliases
+
+        s = s->toAlias();
+        //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
+        for (size_t i = 0; i < idents.dim; i++)
+        {
+            RootObject *id = idents[i];
+
+            if (id->dyncast() == DYNCAST_EXPRESSION ||
+                id->dyncast() == DYNCAST_TYPE)
+            {
+                Type *tx;
+                Expression *ex;
+                Dsymbol *sx;
+                resolveTupleIndex(loc, sc, s, &ex, &tx, &sx, id);
+                if (sx)
+                {
+                    s = sx->toAlias();
+                    continue;
+                }
+                if (tx)
+                    ex = new TypeExp(loc, tx);
+                assert(ex);
+
+                ex = typeToExpressionHelper(this, ex, i + 1);
+                ex = ::semantic(ex, sc);
+                resolveExp(ex, pt, pe, ps);
+                return;
+            }
+
+            Type *t = s->getType();     // type symbol, type alias, or type tuple?
+            unsigned errorsave = global.errors;
+            Dsymbol *sm = s->searchX(loc, sc, id);
+            if (sm && !(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, sm))
+            {
+                ::deprecation(loc, "%s is not visible from module %s", sm->toPrettyChars(), sc->_module->toChars());
+                // sm = NULL;
+            }
+            if (global.errors != errorsave)
+            {
+                *pt = Type::terror;
+                return;
+            }
+            //printf("\t3: s = %p %s %s, sm = %p\n", s, s->kind(), s->toChars(), sm);
+            if (intypeid && !t && sm && sm->needThis())
+                goto L3;
+            if (VarDeclaration *v = s->isVarDeclaration())
+            {
+                if (v->storage_class & (STCconst | STCimmutable | STCmanifest) ||
+                    v->type->isConst() || v->type->isImmutable())
+                {
+                    // Bugzilla 13087: this.field is not constant always
+                    if (!v->isThisDeclaration())
+                        goto L3;
+                }
+            }
+            if (!sm)
+            {
+                if (!t)
+                {
+                    if (s->isDeclaration())         // var, func, or tuple declaration?
+                    {
+                        t = s->isDeclaration()->type;
+                        if (!t && s->isTupleDeclaration())  // expression tuple?
+                            goto L3;
+                    }
+                    else if (s->isTemplateInstance() ||
+                             s->isImport() || s->isPackage() || s->isModule())
+                    {
+                        goto L3;
+                    }
+                }
+                if (t)
+                {
+                    sm = t->toDsymbol(sc);
+                    if (sm && id->dyncast() == DYNCAST_IDENTIFIER)
+                    {
+                        sm = sm->search(loc, (Identifier *)id);
+                        if (sm)
+                            goto L2;
+                    }
+                L3:
+                    Expression *e;
+                    VarDeclaration *v = s->isVarDeclaration();
+                    FuncDeclaration *f = s->isFuncDeclaration();
+                    if (intypeid || !v && !f)
+                        e = ::resolve(loc, sc, s, true);
+                    else
+                        e = new VarExp(loc, s->isDeclaration(), true);
+
+                    e = typeToExpressionHelper(this, e, i);
+                    e = ::semantic(e, sc);
+                    resolveExp(e, pt, pe, ps);
+                    return;
+                }
+                else
+                {
+                    if (id->dyncast() == DYNCAST_DSYMBOL)
+                    {
+                        // searchX already handles errors for template instances
+                        assert(global.errors);
+                    }
+                    else
+                    {
+                        assert(id->dyncast() == DYNCAST_IDENTIFIER);
+                        sm = s->search_correct((Identifier *)id);
+                        if (sm)
+                            error(loc, "identifier '%s' of '%s' is not defined, did you mean %s '%s'?",
+                                  id->toChars(), toChars(), sm->kind(), sm->toChars());
+                        else
+                            error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars());
+                    }
+                    *pe = new ErrorExp();
+                }
+                return;
+            }
+        L2:
+            s = sm->toAlias();
+        }
+
+        if (EnumMember *em = s->isEnumMember())
+        {
+            // It's not a type, it's an expression
+            *pe = em->getVarExp(loc, sc);
+            return;
+        }
+        if (VarDeclaration *v = s->isVarDeclaration())
+        {
+            /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
+             * because some variables used in type context need to prevent lowering
+             * to a literal or contextful expression. For example:
+             *
+             *  enum a = 1; alias b = a;
+             *  template X(alias e){ alias v = e; }  alias x = X!(1);
+             *  struct S { int v; alias w = v; }
+             *      // TypeIdentifier 'a', 'e', and 'v' should be TOKvar,
+             *      // because getDsymbol() need to work in AliasDeclaration::semantic().
+             */
+            if (!v->type ||
+                !v->type->deco && v->inuse)
+            {
+                if (v->inuse)   // Bugzilla 9494
+                    error(loc, "circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+                else
+                    error(loc, "forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+                *pt = Type::terror;
+                return;
+            }
+            if (v->type->ty == Terror)
+                *pt = Type::terror;
+            else
+                *pe = new VarExp(loc, v);
+            return;
+        }
+        if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
+        {
+            //printf("'%s' is a function literal\n", fld->toChars());
+            *pe = new FuncExp(loc, fld);
+            *pe = ::semantic(*pe, sc);
+            return;
+        }
+#if 0
+        if (FuncDeclaration *fd = s->isFuncDeclaration())
+        {
+            *pe = new DsymbolExp(loc, fd);
+            return;
+        }
+#endif
+
+L1:
+        Type *t = s->getType();
+        if (!t)
+        {
+            // If the symbol is an import, try looking inside the import
+            if (Import *si = s->isImport())
+            {
+                s = si->search(loc, s->ident);
+                if (s && s != si)
+                    goto L1;
+                s = si;
+            }
+            *ps = s;
+            return;
+        }
+        if (t->ty == Tinstance && t != this && !t->deco)
+        {
+            if (!((TypeInstance *)t)->tempinst->errors)
+                error(loc, "forward reference to '%s'", t->toChars());
+            *pt = Type::terror;
+            return;
+        }
+
+        if (t->ty == Ttuple)
+            *pt = t;
+        else
+            *pt = t->merge();
+    }
+    if (!s)
+    {
+        const char *p = mutableOf()->unSharedOf()->toChars();
+        const char *n = importHint(p);
+        if (n)
+            error(loc, "'%s' is not defined, perhaps you need to import %s; ?", p, n);
+        else
+        {
+            Identifier *id = new Identifier(p);
+            s = sc->search_correct(id);
+            if (s)
+                error(loc, "undefined identifier '%s', did you mean %s '%s'?", p, s->kind(), s->toChars());
+            else
+                error(loc, "undefined identifier '%s'", p);
+        }
+        *pt = Type::terror;
+    }
+}
+
+/***************************** TypeIdentifier *****************************/
+
+TypeIdentifier::TypeIdentifier(Loc loc, Identifier *ident)
+    : TypeQualified(Tident, loc)
+{
+    this->ident = ident;
+}
+
+const char *TypeIdentifier::kind()
+{
+    return "identifier";
+}
+
+Type *TypeIdentifier::syntaxCopy()
+{
+    TypeIdentifier *t = new TypeIdentifier(loc, ident);
+    t->syntaxCopyHelper(this);
+    t->mod = mod;
+    return t;
+}
+
+/*************************************
+ * Takes an array of Identifiers and figures out if
+ * it represents a Type or an Expression.
+ * Output:
+ *      if expression, *pe is set
+ *      if type, *pt is set
+ */
+
+void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+    //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, toChars());
+
+    if ((ident->equals(Id::_super) || ident->equals(Id::This)) && !hasThis(sc))
+    {
+        AggregateDeclaration *ad = sc->getStructClassScope();
+        if (ad)
+        {
+            ClassDeclaration *cd = ad->isClassDeclaration();
+            if (cd)
+            {
+                if (ident->equals(Id::This))
+                    ident = cd->ident;
+                else if (cd->baseClass && ident->equals(Id::_super))
+                    ident = cd->baseClass->ident;
+            }
+            else
+            {
+                StructDeclaration *sd = ad->isStructDeclaration();
+                if (sd && ident->equals(Id::This))
+                    ident = sd->ident;
+            }
+        }
+    }
+    if (ident == Id::ctfe)
+    {
+        error(loc, "variable __ctfe cannot be read at compile time");
+        *pe = NULL;
+        *ps = NULL;
+        *pt = Type::terror;
+        return;
+    }
+
+    Dsymbol *scopesym;
+    Dsymbol *s = sc->search(loc, ident, &scopesym);
+    resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid);
+    if (*pt)
+        (*pt) = (*pt)->addMod(mod);
+}
+
+/*****************************************
+ * See if type resolves to a symbol, if so,
+ * return that symbol.
+ */
+
+Dsymbol *TypeIdentifier::toDsymbol(Scope *sc)
+{
+    //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
+    if (!sc)
+        return NULL;
+
+    Type *t;
+    Expression *e;
+    Dsymbol *s;
+
+    resolve(loc, sc, &e, &t, &s);
+    if (t && t->ty != Tident)
+        s = t->toDsymbol(sc);
+    if (e)
+        s = getDsymbol(e);
+
+    return s;
+}
+
+Type *TypeIdentifier::semantic(Loc loc, Scope *sc)
+{
+    Type *t;
+    Expression *e;
+    Dsymbol *s;
+
+    //printf("TypeIdentifier::semantic(%s)\n", toChars());
+    resolve(loc, sc, &e, &t, &s);
+    if (t)
+    {
+        //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco);
+        t = t->addMod(mod);
+    }
+    else
+    {
+        if (s)
+        {
+            s->error(loc, "is used as a type");
+            //halt();
+        }
+        else
+            error(loc, "%s is used as a type", toChars());
+        t = terror;
+    }
+    //t->print();
+    return t;
+}
+
+/***************************** TypeInstance *****************************/
+
+TypeInstance::TypeInstance(Loc loc, TemplateInstance *tempinst)
+    : TypeQualified(Tinstance, loc)
+{
+    this->tempinst = tempinst;
+}
+
+const char *TypeInstance::kind()
+{
+    return "instance";
+}
+
+Type *TypeInstance::syntaxCopy()
+{
+    //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim);
+    TypeInstance *t = new TypeInstance(loc, (TemplateInstance *)tempinst->syntaxCopy(NULL));
+    t->syntaxCopyHelper(this);
+    t->mod = mod;
+    return t;
+}
+
+void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+    // Note close similarity to TypeIdentifier::resolve()
+    *pe = NULL;
+    *pt = NULL;
+    *ps = NULL;
+    //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, tempinst->toChars());
+    tempinst->semantic(sc);
+    if (!global.gag && tempinst->errors)
+    {
+        *pt = terror;
+        return;
+    }
+
+    resolveHelper(loc, sc, tempinst, NULL, pe, pt, ps, intypeid);
+    if (*pt)
+        *pt = (*pt)->addMod(mod);
+    //if (*pt) printf("pt = '%s'\n", (*pt)->toChars());
+}
+
+Type *TypeInstance::semantic(Loc loc, Scope *sc)
+{
+    Type *t;
+    Expression *e;
+    Dsymbol *s;
+
+    //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
+    {
+        unsigned errors = global.errors;
+        resolve(loc, sc, &e, &t, &s);
+        // if we had an error evaluating the symbol, suppress further errors
+        if (!t && errors != global.errors)
+            return terror;
+    }
+
+    if (!t)
+    {
+        if (!e && s && s->errors)
+        {
+            // if there was an error evaluating the symbol, it might actually
+            // be a type. Avoid misleading error messages.
+            error(loc, "%s had previous errors", toChars());
+        }
+        else
+            error(loc, "%s is used as a type", toChars());
+        t = terror;
+    }
+    return t;
+}
+
+Dsymbol *TypeInstance::toDsymbol(Scope *sc)
+{
+    Type *t;
+    Expression *e;
+    Dsymbol *s;
+
+    //printf("TypeInstance::semantic(%s)\n", toChars());
+    resolve(loc, sc, &e, &t, &s);
+    if (t && t->ty != Tinstance)
+        s = t->toDsymbol(sc);
+
+    return s;
+}
+
+
+/***************************** TypeTypeof *****************************/
+
+TypeTypeof::TypeTypeof(Loc loc, Expression *exp)
+        : TypeQualified(Ttypeof, loc)
+{
+    this->exp = exp;
+    inuse = 0;
+}
+
+const char *TypeTypeof::kind()
+{
+    return "typeof";
+}
+
+Type *TypeTypeof::syntaxCopy()
+{
+    //printf("TypeTypeof::syntaxCopy() %s\n", toChars());
+    TypeTypeof *t = new TypeTypeof(loc, exp->syntaxCopy());
+    t->syntaxCopyHelper(this);
+    t->mod = mod;
+    return t;
+}
+
+Dsymbol *TypeTypeof::toDsymbol(Scope *sc)
+{
+    //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
+    Expression *e;
+    Type *t;
+    Dsymbol *s;
+    resolve(loc, sc, &e, &t, &s);
+
+    return s;
+}
+
+void TypeTypeof::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+    *pe = NULL;
+    *pt = NULL;
+    *ps = NULL;
+
+    //printf("TypeTypeof::resolve(sc = %p, idents = '%s')\n", sc, toChars());
+    //static int nest; if (++nest == 50) *(char*)0=0;
+    if (inuse)
+    {
+        inuse = 2;
+        error(loc, "circular typeof definition");
+    Lerr:
+        *pt = Type::terror;
+        inuse--;
+        return;
+    }
+    inuse++;
+
+    Type *t;
+    {
+        /* Currently we cannot evalute 'exp' in speculative context, because
+         * the type implementation may leak to the final execution. Consider:
+         *
+         * struct S(T) {
+         *   string toString() const { return "x"; }
+         * }
+         * void main() {
+         *   alias X = typeof(S!int());
+         *   assert(typeid(X).xtoString(null) == "x");
+         * }
+         */
+        Scope *sc2 = sc->push();
+        sc2->intypeof = 1;
+        Expression *exp2 = ::semantic(exp, sc2);
+        exp2 = resolvePropertiesOnly(sc2, exp2);
+        sc2->pop();
+
+        if (exp2->op == TOKerror)
+        {
+            if (!global.gag)
+                exp = exp2;
+            goto Lerr;
+        }
+        exp = exp2;
+
+        if (exp->op == TOKtype ||
+            exp->op == TOKscope)
+        {
+            if (exp->checkType())
+                goto Lerr;
+
+            /* Today, 'typeof(func)' returns void if func is a
+             * function template (TemplateExp), or
+             * template lambda (FuncExp).
+             * It's actually used in Phobos as an idiom, to branch code for
+             * template functions.
+             */
+        }
+        if (FuncDeclaration *f = exp->op == TOKvar    ? ((   VarExp *)exp)->var->isFuncDeclaration()
+                               : exp->op == TOKdotvar ? ((DotVarExp *)exp)->var->isFuncDeclaration() : NULL)
+        {
+            if (f->checkForwardRef(loc))
+                goto Lerr;
+        }
+        if (FuncDeclaration *f = isFuncAddress(exp))
+        {
+            if (f->checkForwardRef(loc))
+                goto Lerr;
+        }
+
+        t = exp->type;
+        if (!t)
+        {
+            error(loc, "expression (%s) has no type", exp->toChars());
+            goto Lerr;
+        }
+        if (t->ty == Ttypeof)
+        {
+            error(loc, "forward reference to %s", toChars());
+            goto Lerr;
+        }
+    }
+    if (idents.dim == 0)
+        *pt = t;
+    else
+    {
+        if (Dsymbol *s = t->toDsymbol(sc))
+            resolveHelper(loc, sc, s, NULL, pe, pt, ps, intypeid);
+        else
+        {
+            Expression *e = typeToExpressionHelper(this, new TypeExp(loc, t));
+            e = ::semantic(e, sc);
+            resolveExp(e, pt, pe, ps);
+        }
+    }
+    if (*pt)
+        (*pt) = (*pt)->addMod(mod);
+    inuse--;
+    return;
+}
+
+Type *TypeTypeof::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeTypeof::semantic() %s\n", toChars());
+
+    Expression *e;
+    Type *t;
+    Dsymbol *s;
+    resolve(loc, sc, &e, &t, &s);
+    if (s && (t = s->getType()) != NULL)
+        t = t->addMod(mod);
+    if (!t)
+    {
+        error(loc, "%s is used as a type", toChars());
+        t = Type::terror;
+    }
+    return t;
+}
+
+d_uns64 TypeTypeof::size(Loc loc)
+{
+    if (exp->type)
+        return exp->type->size(loc);
+    else
+        return TypeQualified::size(loc);
+}
+
+
+
+/***************************** TypeReturn *****************************/
+
+TypeReturn::TypeReturn(Loc loc)
+        : TypeQualified(Treturn, loc)
+{
+}
+
+const char *TypeReturn::kind()
+{
+    return "return";
+}
+
+Type *TypeReturn::syntaxCopy()
+{
+    TypeReturn *t = new TypeReturn(loc);
+    t->syntaxCopyHelper(this);
+    t->mod = mod;
+    return t;
+}
+
+Dsymbol *TypeReturn::toDsymbol(Scope *sc)
+{
+    Expression *e;
+    Type *t;
+    Dsymbol *s;
+    resolve(loc, sc, &e, &t, &s);
+
+    return s;
+}
+
+void TypeReturn::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+    *pe = NULL;
+    *pt = NULL;
+    *ps = NULL;
+
+    //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, toChars());
+    Type *t;
+    {
+        FuncDeclaration *func = sc->func;
+        if (!func)
+        {
+            error(loc, "typeof(return) must be inside function");
+            goto Lerr;
+        }
+        if (func->fes)
+            func = func->fes->func;
+
+        t = func->type->nextOf();
+        if (!t)
+        {
+            error(loc, "cannot use typeof(return) inside function %s with inferred return type", sc->func->toChars());
+            goto Lerr;
+        }
+    }
+    if (idents.dim == 0)
+        *pt = t;
+    else
+    {
+        if (Dsymbol *s = t->toDsymbol(sc))
+            resolveHelper(loc, sc, s, NULL, pe, pt, ps, intypeid);
+        else
+        {
+            Expression *e = typeToExpressionHelper(this, new TypeExp(loc, t));
+            e = ::semantic(e, sc);
+            resolveExp(e, pt, pe, ps);
+        }
+    }
+    if (*pt)
+        (*pt) = (*pt)->addMod(mod);
+    return;
+
+Lerr:
+    *pt = Type::terror;
+    return;
+}
+
+Type *TypeReturn::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeReturn::semantic() %s\n", toChars());
+
+    Expression *e;
+    Type *t;
+    Dsymbol *s;
+    resolve(loc, sc, &e, &t, &s);
+    if (s && (t = s->getType()) != NULL)
+        t = t->addMod(mod);
+    if (!t)
+    {
+        error(loc, "%s is used as a type", toChars());
+        t = Type::terror;
+    }
+    return t;
+}
+
+/***************************** TypeEnum *****************************/
+
+TypeEnum::TypeEnum(EnumDeclaration *sym)
+        : Type(Tenum)
+{
+    this->sym = sym;
+}
+
+const char *TypeEnum::kind()
+{
+    return "enum";
+}
+
+Type *TypeEnum::syntaxCopy()
+{
+    return this;
+}
+
+Type *TypeEnum::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeEnum::semantic() %s\n", toChars());
+    if (deco)
+        return this;
+    return merge();
+}
+
+d_uns64 TypeEnum::size(Loc loc)
+{
+    return sym->getMemtype(loc)->size(loc);
+}
+
+unsigned TypeEnum::alignsize()
+{
+    Type *t = sym->getMemtype(Loc());
+    if (t->ty == Terror)
+        return 4;
+    return t->alignsize();
+}
+
+Dsymbol *TypeEnum::toDsymbol(Scope *sc)
+{
+    return sym;
+}
+
+Type *TypeEnum::toBasetype()
+{
+    if (!sym->members && !sym->memtype)
+        return this;
+    Type *tb = sym->getMemtype(Loc())->toBasetype();
+    return tb->castMod(mod);         // retain modifier bits from 'this'
+}
+
+Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+#if LOGDOTEXP
+    printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars());
+#endif
+    // Bugzilla 14010
+    if (ident == Id::_mangleof)
+        return getProperty(e->loc, ident, flag & 1);
+
+    if (sym->_scope)
+        sym->semantic(sym->_scope);
+    if (!sym->members)
+    {
+        if (!(flag & 1))
+        {
+            sym->error("is forward referenced when looking for '%s'", ident->toChars());
+            e = new ErrorExp();
+        }
+        else
+            e = NULL;
+        return e;
+    }
+
+    Dsymbol *s = sym->search(e->loc, ident);
+    if (!s)
+    {
+        if (ident == Id::max ||
+            ident == Id::min ||
+            ident == Id::_init)
+        {
+            return getProperty(e->loc, ident, flag & 1);
+        }
+        Expression *res = sym->getMemtype(Loc())->dotExp(sc, e, ident, 1);
+        if (!(flag & 1) && !res)
+        {
+            if (Dsymbol *ns = sym->search_correct(ident))
+                e->error("no property '%s' for type '%s'. Did you mean '%s.%s' ?",
+                    ident->toChars(), toChars(), toChars(), ns->toChars());
+            else
+                e->error("no property '%s' for type '%s'",
+                    ident->toChars(), toChars());
+
+            return new ErrorExp();
+        }
+        return res;
+    }
+    EnumMember *m = s->isEnumMember();
+    return m->getVarExp(e->loc, sc);
+}
+
+Expression *TypeEnum::getProperty(Loc loc, Identifier *ident, int flag)
+{
+    Expression *e;
+    if (ident == Id::max || ident == Id::min)
+    {
+        return sym->getMaxMinValue(loc, ident);
+    }
+    else if (ident == Id::_init)
+    {
+        e = defaultInitLiteral(loc);
+    }
+    else if (ident == Id::stringof)
+    {
+        const char *s = toChars();
+        e = new StringExp(loc, (char *)s, strlen(s));
+        Scope sc;
+        e = ::semantic(e, &sc);
+    }
+    else if (ident == Id::_mangleof)
+    {
+        e = Type::getProperty(loc, ident, flag);
+    }
+    else
+    {
+        e = toBasetype()->getProperty(loc, ident, flag);
+    }
+    return e;
+}
+
+bool TypeEnum::isintegral()
+{
+    return sym->getMemtype(Loc())->isintegral();
+}
+
+bool TypeEnum::isfloating()
+{
+    return sym->getMemtype(Loc())->isfloating();
+}
+
+bool TypeEnum::isreal()
+{
+    return sym->getMemtype(Loc())->isreal();
+}
+
+bool TypeEnum::isimaginary()
+{
+    return sym->getMemtype(Loc())->isimaginary();
+}
+
+bool TypeEnum::iscomplex()
+{
+    return sym->getMemtype(Loc())->iscomplex();
+}
+
+bool TypeEnum::isunsigned()
+{
+    return sym->getMemtype(Loc())->isunsigned();
+}
+
+bool TypeEnum::isscalar()
+{
+    return sym->getMemtype(Loc())->isscalar();
+}
+
+bool TypeEnum::isString()
+{
+    return sym->getMemtype(Loc())->isString();
+}
+
+bool TypeEnum::isAssignable()
+{
+    return sym->getMemtype(Loc())->isAssignable();
+}
+
+bool TypeEnum::isBoolean()
+{
+    return sym->getMemtype(Loc())->isBoolean();
+}
+
+bool TypeEnum::needsDestruction()
+{
+    return sym->getMemtype(Loc())->needsDestruction();
+}
+
+bool TypeEnum::needsNested()
+{
+    return sym->getMemtype(Loc())->needsNested();
+}
+
+MATCH TypeEnum::implicitConvTo(Type *to)
+{
+    MATCH m;
+
+    //printf("TypeEnum::implicitConvTo()\n");
+    if (ty == to->ty && sym == ((TypeEnum *)to)->sym)
+        m = (mod == to->mod) ? MATCHexact : MATCHconst;
+    else if (sym->getMemtype(Loc())->implicitConvTo(to))
+        m = MATCHconvert;       // match with conversions
+    else
+        m = MATCHnomatch;       // no match
+    return m;
+}
+
+MATCH TypeEnum::constConv(Type *to)
+{
+    if (equals(to))
+        return MATCHexact;
+    if (ty == to->ty && sym == ((TypeEnum *)to)->sym &&
+        MODimplicitConv(mod, to->mod))
+        return MATCHconst;
+    return MATCHnomatch;
+}
+
+
+Expression *TypeEnum::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeEnum::defaultInit() '%s'\n", toChars());
+#endif
+    // Initialize to first member of enum
+    Expression *e = sym->getDefaultValue(loc);
+    e = e->copy();
+    e->loc = loc;
+    e->type = this;     // to deal with const, immutable, etc., variants
+    return e;
+}
+
+bool TypeEnum::isZeroInit(Loc loc)
+{
+    return sym->getDefaultValue(loc)->isBool(false);
+}
+
+bool TypeEnum::hasPointers()
+{
+    return sym->getMemtype(Loc())->hasPointers();
+}
+
+bool TypeEnum::hasVoidInitPointers()
+{
+    return sym->getMemtype(Loc())->hasVoidInitPointers();
+}
+
+Type *TypeEnum::nextOf()
+{
+    return sym->getMemtype(Loc())->nextOf();
+}
+
+/***************************** TypeStruct *****************************/
+
+TypeStruct::TypeStruct(StructDeclaration *sym)
+        : Type(Tstruct)
+{
+    this->sym = sym;
+    this->att = RECfwdref;
+    this->cppmangle = CPPMANGLEdefault;
+}
+
+TypeStruct *TypeStruct::create(StructDeclaration *sym)
+{
+    return new TypeStruct(sym);
+}
+
+const char *TypeStruct::kind()
+{
+    return "struct";
+}
+
+Type *TypeStruct::syntaxCopy()
+{
+    return this;
+}
+
+Type *TypeStruct::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeStruct::semantic('%s')\n", sym->toChars());
+    if (deco)
+    {
+        if (sc && sc->cppmangle != CPPMANGLEdefault)
+        {
+            if (this->cppmangle == CPPMANGLEdefault)
+                this->cppmangle = sc->cppmangle;
+            else
+                assert(this->cppmangle == sc->cppmangle);
+        }
+        return this;
+    }
+
+    /* Don't semantic for sym because it should be deferred until
+     * sizeof needed or its members accessed.
+     */
+    // instead, parent should be set correctly
+    assert(sym->parent);
+
+    if (sym->type->ty == Terror)
+        return Type::terror;
+    if (sc)
+        this->cppmangle = sc->cppmangle;
+    return merge();
+}
+
+d_uns64 TypeStruct::size(Loc loc)
+{
+    return sym->size(loc);
+}
+
+unsigned TypeStruct::alignsize()
+{
+    sym->size(Loc());               // give error for forward references
+    return sym->alignsize;
+}
+
+Dsymbol *TypeStruct::toDsymbol(Scope *sc)
+{
+    return sym;
+}
+
+static Dsymbol *searchSymStruct(Scope *sc, Dsymbol *sym, Expression *e, Identifier *ident)
+{
+    int flags = sc->flags & SCOPEignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
+    Dsymbol *sold = NULL;
+    if (global.params.bug10378 || global.params.check10378)
+    {
+        sold = sym->search(e->loc, ident, flags);
+        if (!global.params.check10378)
+            return sold;
+    }
+
+    Dsymbol *s = sym->search(e->loc, ident, flags | SearchLocalsOnly);
+    if (global.params.check10378)
+    {
+        Dsymbol *snew = s;
+        if (sold != snew)
+            Scope::deprecation10378(e->loc, sold, snew);
+        if (global.params.bug10378)
+            s = sold;
+    }
+    return s;
+}
+
+Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+    Dsymbol *s;
+
+#if LOGDOTEXP
+    printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    assert(e->op != TOKdot);
+
+    // Bugzilla 14010
+    if (ident == Id::_mangleof)
+        return getProperty(e->loc, ident, flag & 1);
+
+    /* If e.tupleof
+     */
+    if (ident == Id::_tupleof)
+    {
+        /* Create a TupleExp out of the fields of the struct e:
+         * (e.field0, e.field1, e.field2, ...)
+         */
+        e = ::semantic(e, sc);  // do this before turning on noaccesscheck
+
+        sym->size(e->loc);      // do semantic of type
+
+        Expression *e0 = NULL;
+        Expression *ev = e->op == TOKtype ? NULL : e;
+        if (ev)
+            ev = extractSideEffect(sc, "__tup", &e0, ev);
+
+        Expressions *exps = new Expressions;
+        exps->reserve(sym->fields.dim);
+        for (size_t i = 0; i < sym->fields.dim; i++)
+        {
+            VarDeclaration *v = sym->fields[i];
+            Expression *ex;
+            if (ev)
+                ex = new DotVarExp(e->loc, ev, v);
+            else
+            {
+                ex = new VarExp(e->loc, v);
+                ex->type = ex->type->addMod(e->type->mod);
+            }
+            exps->push(ex);
+        }
+
+        e = new TupleExp(e->loc, e0, exps);
+        Scope *sc2 = sc->push();
+        sc2->flags = sc->flags | SCOPEnoaccesscheck;
+        e = ::semantic(e, sc2);
+        sc2->pop();
+        return e;
+    }
+
+    s = searchSymStruct(sc, sym, e, ident);
+L1:
+    if (!s)
+    {
+        return noMember(sc, e, ident, flag);
+    }
+    if (!(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, s))
+    {
+        ::deprecation(e->loc, "%s is not visible from module %s", s->toPrettyChars(), sc->_module->toPrettyChars());
+        // return noMember(sc, e, ident, flag);
+    }
+    if (!s->isFuncDeclaration())        // because of overloading
+        s->checkDeprecated(e->loc, sc);
+    s = s->toAlias();
+
+    EnumMember *em = s->isEnumMember();
+    if (em)
+    {
+        return em->getVarExp(e->loc, sc);
+    }
+
+    if (VarDeclaration *v = s->isVarDeclaration())
+    {
+        if (!v->type ||
+            !v->type->deco && v->inuse)
+        {
+            if (v->inuse) // Bugzilla 9494
+                e->error("circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+            else
+                e->error("forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+            return new ErrorExp();
+        }
+        if (v->type->ty == Terror)
+            return new ErrorExp();
+
+        if ((v->storage_class & STCmanifest) && v->_init)
+        {
+            if (v->inuse)
+            {
+                e->error("circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+                return new ErrorExp();
+            }
+            checkAccess(e->loc, sc, NULL, v);
+            Expression *ve = new VarExp(e->loc, v);
+            ve = ::semantic(ve, sc);
+            return ve;
+        }
+    }
+
+    if (s->getType())
+    {
+        return new TypeExp(e->loc, s->getType());
+    }
+
+    TemplateMixin *tm = s->isTemplateMixin();
+    if (tm)
+    {
+        Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
+        de->type = e->type;
+        return de;
+    }
+
+    TemplateDeclaration *td = s->isTemplateDeclaration();
+    if (td)
+    {
+        if (e->op == TOKtype)
+            e = new ScopeExp(e->loc, td);
+        else
+            e = new DotTemplateExp(e->loc, e, td);
+        e = ::semantic(e, sc);
+        return e;
+    }
+
+    TemplateInstance *ti = s->isTemplateInstance();
+    if (ti)
+    {
+        if (!ti->semanticRun)
+        {
+            ti->semantic(sc);
+            if (!ti->inst || ti->errors)    // if template failed to expand
+                return new ErrorExp();
+        }
+        s = ti->inst->toAlias();
+        if (!s->isTemplateInstance())
+            goto L1;
+        if (e->op == TOKtype)
+            e = new ScopeExp(e->loc, ti);
+        else
+            e = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
+        return ::semantic(e, sc);
+    }
+
+    if (s->isImport() || s->isModule() || s->isPackage())
+    {
+        e = ::resolve(e->loc, sc, s, false);
+        return e;
+    }
+
+    OverloadSet *o = s->isOverloadSet();
+    if (o)
+    {
+        OverExp *oe = new OverExp(e->loc, o);
+        if (e->op == TOKtype)
+            return oe;
+        return new DotExp(e->loc, e, oe);
+    }
+
+    Declaration *d = s->isDeclaration();
+    if (!d)
+    {
+        e->error("%s.%s is not a declaration", e->toChars(), ident->toChars());
+        return new ErrorExp();
+    }
+
+    if (e->op == TOKtype)
+    {
+        /* It's:
+         *    Struct.d
+         */
+        if (TupleDeclaration *tup = d->isTupleDeclaration())
+        {
+            e = new TupleExp(e->loc, tup);
+            e = ::semantic(e, sc);
+            return e;
+        }
+        if (d->needThis() && sc->intypeof != 1)
+        {
+            /* Rewrite as:
+             *  this.d
+             */
+            if (hasThis(sc))
+            {
+                e = new DotVarExp(e->loc, new ThisExp(e->loc), d);
+                e = ::semantic(e, sc);
+                return e;
+            }
+        }
+        if (d->semanticRun == PASSinit && d->_scope)
+            d->semantic(d->_scope);
+        checkAccess(e->loc, sc, e, d);
+        VarExp *ve = new VarExp(e->loc, d);
+        if (d->isVarDeclaration() && d->needThis())
+            ve->type = d->type->addMod(e->type->mod);
+        return ve;
+    }
+
+    bool unreal = e->op == TOKvar && ((VarExp *)e)->var->isField();
+    if (d->isDataseg() || unreal && d->isField())
+    {
+        // (e, d)
+        checkAccess(e->loc, sc, e, d);
+        Expression *ve = new VarExp(e->loc, d);
+        e = unreal ? ve : new CommaExp(e->loc, e, ve);
+        e = ::semantic(e, sc);
+        return e;
+    }
+
+    e = new DotVarExp(e->loc, e, d);
+    e = ::semantic(e, sc);
+    return e;
+}
+
+structalign_t TypeStruct::alignment()
+{
+    if (sym->alignment == 0)
+        sym->size(sym->loc);
+    return sym->alignment;
+}
+
+Expression *TypeStruct::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeStruct::defaultInit() '%s'\n", toChars());
+#endif
+    Declaration *d = new SymbolDeclaration(sym->loc, sym);
+    assert(d);
+    d->type = this;
+    d->storage_class |= STCrvalue;      // Bugzilla 14398
+    return new VarExp(sym->loc, d);
+}
+
+/***************************************
+ * Use when we prefer the default initializer to be a literal,
+ * rather than a global immutable variable.
+ */
+Expression *TypeStruct::defaultInitLiteral(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars());
+#endif
+    sym->size(loc);
+    if (sym->sizeok != SIZEOKdone)
+        return new ErrorExp();
+    Expressions *structelems = new Expressions();
+    structelems->setDim(sym->fields.dim - sym->isNested());
+    unsigned offset = 0;
+    for (size_t j = 0; j < structelems->dim; j++)
+    {
+        VarDeclaration *vd = sym->fields[j];
+        Expression *e;
+        if (vd->inuse)
+        {
+            error(loc, "circular reference to '%s'", vd->toPrettyChars());
+            return new ErrorExp();
+        }
+        if (vd->offset < offset || vd->type->size() == 0)
+            e = NULL;
+        else if (vd->_init)
+        {
+            if (vd->_init->isVoidInitializer())
+                e = NULL;
+            else
+                e = vd->getConstInitializer(false);
+        }
+        else
+            e = vd->type->defaultInitLiteral(loc);
+        if (e && e->op == TOKerror)
+            return e;
+        if (e)
+            offset = vd->offset + (unsigned)vd->type->size();
+        (*structelems)[j] = e;
+    }
+    StructLiteralExp *structinit = new StructLiteralExp(loc, (StructDeclaration *)sym, structelems);
+
+    /* Copy from the initializer symbol for larger symbols,
+     * otherwise the literals expressed as code get excessively large.
+     */
+    if (size(loc) > Target::ptrsize * 4 && !needsNested())
+        structinit->useStaticInit = true;
+
+    structinit->type = this;
+    return structinit;
+}
+
+
+bool TypeStruct::isZeroInit(Loc loc)
+{
+    return sym->zeroInit != 0;
+}
+
+bool TypeStruct::isBoolean()
+{
+    return false;
+}
+
+bool TypeStruct::needsDestruction()
+{
+    return sym->dtor != NULL;
+}
+
+bool TypeStruct::needsNested()
+{
+    if (sym->isNested())
+        return true;
+
+    for (size_t i = 0; i < sym->fields.dim; i++)
+    {
+        VarDeclaration *v = sym->fields[i];
+        if (!v->isDataseg() && v->type->needsNested())
+            return true;
+    }
+    return false;
+}
+
+bool TypeStruct::isAssignable()
+{
+    bool assignable = true;
+    unsigned offset = ~0;  // dead-store initialize to prevent spurious warning
+
+    /* If any of the fields are const or immutable,
+     * then one cannot assign this struct.
+     */
+    for (size_t i = 0; i < sym->fields.dim; i++)
+    {
+        VarDeclaration *v = sym->fields[i];
+        //printf("%s [%d] v = (%s) %s, v->offset = %d, v->parent = %s", sym->toChars(), i, v->kind(), v->toChars(), v->offset, v->parent->kind());
+        if (i == 0)
+            ;
+        else if (v->offset == offset)
+        {
+            /* If any fields of anonymous union are assignable,
+             * then regard union as assignable.
+             * This is to support unsafe things like Rebindable templates.
+             */
+            if (assignable)
+                continue;
+        }
+        else
+        {
+            if (!assignable)
+                return false;
+        }
+        assignable = v->type->isMutable() && v->type->isAssignable();
+        offset = v->offset;
+        //printf(" -> assignable = %d\n", assignable);
+    }
+
+    return assignable;
+}
+
+bool TypeStruct::hasPointers()
+{
+    // Probably should cache this information in sym rather than recompute
+    StructDeclaration *s = sym;
+
+    sym->size(Loc());               // give error for forward references
+    for (size_t i = 0; i < s->fields.dim; i++)
+    {
+        Declaration *d = s->fields[i];
+        if (d->storage_class & STCref || d->hasPointers())
+            return true;
+    }
+    return false;
+}
+
+bool TypeStruct::hasVoidInitPointers()
+{
+    // Probably should cache this information in sym rather than recompute
+    StructDeclaration *s = sym;
+
+    sym->size(Loc()); // give error for forward references
+    for (size_t i = 0; i < s->fields.dim; i++)
+    {
+        VarDeclaration *v = s->fields[i];
+        if (v->_init && v->_init->isVoidInitializer() && v->type->hasPointers())
+            return true;
+        if (!v->_init && v->type->hasVoidInitPointers())
+            return true;
+    }
+    return false;
+}
+
+MATCH TypeStruct::implicitConvTo(Type *to)
+{   MATCH m;
+
+    //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to->toChars());
+
+    if (ty == to->ty && sym == ((TypeStruct *)to)->sym)
+    {
+        m = MATCHexact;         // exact match
+        if (mod != to->mod)
+        {
+            m = MATCHconst;
+            if (MODimplicitConv(mod, to->mod))
+                ;
+            else
+            {
+                /* Check all the fields. If they can all be converted,
+                 * allow the conversion.
+                 */
+                unsigned offset = ~0;   // dead-store to prevent spurious warning
+                for (size_t i = 0; i < sym->fields.dim; i++)
+                {
+                    VarDeclaration *v = sym->fields[i];
+                    if (i == 0)
+                        ;
+                    else if (v->offset == offset)
+                    {
+                        if (m > MATCHnomatch)
+                            continue;
+                    }
+                    else
+                    {
+                        if (m <= MATCHnomatch)
+                            return m;
+                    }
+
+                    // 'from' type
+                    Type *tvf = v->type->addMod(mod);
+
+                    // 'to' type
+                    Type *tv = v->type->addMod(to->mod);
+
+                    // field match
+                    MATCH mf = tvf->implicitConvTo(tv);
+                    //printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), mf);
+
+                    if (mf <= MATCHnomatch)
+                        return mf;
+                    if (mf < m)         // if field match is worse
+                        m = mf;
+                    offset = v->offset;
+                }
+            }
+        }
+    }
+    else if (sym->aliasthis && !(att & RECtracing))
+    {
+        att = (AliasThisRec)(att | RECtracing);
+        m = aliasthisOf()->implicitConvTo(to);
+        att = (AliasThisRec)(att & ~RECtracing);
+    }
+    else
+        m = MATCHnomatch;       // no match
+    return m;
+}
+
+MATCH TypeStruct::constConv(Type *to)
+{
+    if (equals(to))
+        return MATCHexact;
+    if (ty == to->ty && sym == ((TypeStruct *)to)->sym &&
+        MODimplicitConv(mod, to->mod))
+        return MATCHconst;
+    return MATCHnomatch;
+}
+
+unsigned char TypeStruct::deduceWild(Type *t, bool isRef)
+{
+    if (ty == t->ty && sym == ((TypeStruct *)t)->sym)
+        return Type::deduceWild(t, isRef);
+
+    unsigned char wm = 0;
+
+    if (t->hasWild() && sym->aliasthis && !(att & RECtracing))
+    {
+        att = (AliasThisRec)(att | RECtracing);
+        wm = aliasthisOf()->deduceWild(t, isRef);
+        att = (AliasThisRec)(att & ~RECtracing);
+    }
+
+    return wm;
+}
+
+Type *TypeStruct::toHeadMutable()
+{
+    return this;
+}
+
+
+/***************************** TypeClass *****************************/
+
+TypeClass::TypeClass(ClassDeclaration *sym)
+        : Type(Tclass)
+{
+    this->sym = sym;
+    this->att = RECfwdref;
+    this->cppmangle = CPPMANGLEdefault;
+}
+
+const char *TypeClass::kind()
+{
+    return "class";
+}
+
+Type *TypeClass::syntaxCopy()
+{
+    return this;
+}
+
+Type *TypeClass::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeClass::semantic(%s)\n", sym->toChars());
+    if (deco)
+    {
+        if (sc && sc->cppmangle != CPPMANGLEdefault)
+        {
+            if (this->cppmangle == CPPMANGLEdefault)
+                this->cppmangle = sc->cppmangle;
+            else
+                assert(this->cppmangle == sc->cppmangle);
+        }
+        return this;
+    }
+
+    /* Don't semantic for sym because it should be deferred until
+     * sizeof needed or its members accessed.
+     */
+    // instead, parent should be set correctly
+    assert(sym->parent);
+
+    if (sym->type->ty == Terror)
+        return Type::terror;
+    if (sc)
+        this->cppmangle = sc->cppmangle;
+    return merge();
+}
+
+d_uns64 TypeClass::size(Loc loc)
+{
+    return Target::ptrsize;
+}
+
+Dsymbol *TypeClass::toDsymbol(Scope *sc)
+{
+    return sym;
+}
+
+static Dsymbol *searchSymClass(Scope *sc, Dsymbol *sym, Expression *e, Identifier *ident)
+{
+    int flags = sc->flags & SCOPEignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
+    Dsymbol *sold = NULL;
+    if (global.params.bug10378 || global.params.check10378)
+    {
+        sold = sym->search(e->loc, ident, flags | IgnoreSymbolVisibility);
+        if (!global.params.check10378)
+            return sold;
+    }
+
+    Dsymbol *s = sym->search(e->loc, ident, flags | SearchLocalsOnly);
+    if (!s && !(flags & IgnoreSymbolVisibility))
+    {
+        s = sym->search(e->loc, ident, flags | SearchLocalsOnly | IgnoreSymbolVisibility);
+        if (s && !(flags & IgnoreErrors))
+            ::deprecation(e->loc, "%s is not visible from class %s", s->toPrettyChars(), sym->toChars());
+    }
+    if (global.params.check10378)
+    {
+        Dsymbol *snew = s;
+        if (sold != snew)
+            Scope::deprecation10378(e->loc, sold, snew);
+        if (global.params.bug10378)
+            s = sold;
+    }
+    return s;
+}
+
+Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+    Dsymbol *s;
+#if LOGDOTEXP
+    printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    assert(e->op != TOKdot);
+
+    // Bugzilla 12543
+    if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::_mangleof)
+    {
+        return Type::getProperty(e->loc, ident, 0);
+    }
+
+    /* If e.tupleof
+     */
+    if (ident == Id::_tupleof)
+    {
+        /* Create a TupleExp
+         */
+        e = ::semantic(e, sc);  // do this before turning on noaccesscheck
+
+        sym->size(e->loc); // do semantic of type
+
+        Expression *e0 = NULL;
+        Expression *ev = e->op == TOKtype ? NULL : e;
+        if (ev)
+            ev = extractSideEffect(sc, "__tup", &e0, ev);
+
+        Expressions *exps = new Expressions;
+        exps->reserve(sym->fields.dim);
+        for (size_t i = 0; i < sym->fields.dim; i++)
+        {
+            VarDeclaration *v = sym->fields[i];
+            // Don't include hidden 'this' pointer
+            if (v->isThisDeclaration())
+                continue;
+            Expression *ex;
+            if (ev)
+                ex = new DotVarExp(e->loc, ev, v);
+            else
+            {
+                ex = new VarExp(e->loc, v);
+                ex->type = ex->type->addMod(e->type->mod);
+            }
+            exps->push(ex);
+        }
+
+        e = new TupleExp(e->loc, e0, exps);
+        Scope *sc2 = sc->push();
+        sc2->flags = sc->flags | SCOPEnoaccesscheck;
+        e = ::semantic(e, sc2);
+        sc2->pop();
+        return e;
+    }
+
+    s = searchSymClass(sc, sym, e, ident);
+L1:
+    if (!s)
+    {
+        // See if it's 'this' class or a base class
+        if (sym->ident == ident)
+        {
+            if (e->op == TOKtype)
+                return Type::getProperty(e->loc, ident, 0);
+            return new DotTypeExp(e->loc, e, sym);
+        }
+        if (ClassDeclaration *cbase = sym->searchBase(ident))
+        {
+            if (e->op == TOKtype)
+                return Type::getProperty(e->loc, ident, 0);
+            if (InterfaceDeclaration *ifbase = cbase->isInterfaceDeclaration())
+                e = new CastExp(e->loc, e, ifbase->type);
+            else
+                e = new DotTypeExp(e->loc, e, cbase);
+            return e;
+        }
+
+        if (ident == Id::classinfo)
+        {
+            assert(Type::typeinfoclass);
+            Type *t = Type::typeinfoclass->type;
+            if (e->op == TOKtype || e->op == TOKdottype)
+            {
+                /* For type.classinfo, we know the classinfo
+                 * at compile time.
+                 */
+                if (!sym->vclassinfo)
+                    sym->vclassinfo = new TypeInfoClassDeclaration(sym->type);
+                e = new VarExp(e->loc, sym->vclassinfo);
+                e = e->addressOf();
+                e->type = t;    // do this so we don't get redundant dereference
+            }
+            else
+            {
+                /* For class objects, the classinfo reference is the first
+                 * entry in the vtbl[]
+                 */
+                e = new PtrExp(e->loc, e);
+                e->type = t->pointerTo();
+                if (sym->isInterfaceDeclaration())
+                {
+                    if (sym->isCPPinterface())
+                    {
+                        /* C++ interface vtbl[]s are different in that the
+                         * first entry is always pointer to the first virtual
+                         * function, not classinfo.
+                         * We can't get a .classinfo for it.
+                         */
+                        error(e->loc, "no .classinfo for C++ interface objects");
+                    }
+                    /* For an interface, the first entry in the vtbl[]
+                     * is actually a pointer to an instance of struct Interface.
+                     * The first member of Interface is the .classinfo,
+                     * so add an extra pointer indirection.
+                     */
+                    e->type = e->type->pointerTo();
+                    e = new PtrExp(e->loc, e);
+                    e->type = t->pointerTo();
+                }
+                e = new PtrExp(e->loc, e, t);
+            }
+            return e;
+        }
+
+        if (ident == Id::__vptr)
+        {
+            /* The pointer to the vtbl[]
+             * *cast(immutable(void*)**)e
+             */
+            e = e->castTo(sc, tvoidptr->immutableOf()->pointerTo()->pointerTo());
+            e = new PtrExp(e->loc, e);
+            e = ::semantic(e, sc);
+            return e;
+        }
+
+        if (ident == Id::__monitor)
+        {
+            /* The handle to the monitor (call it a void*)
+             * *(cast(void**)e + 1)
+             */
+            e = e->castTo(sc, tvoidptr->pointerTo());
+            e = new AddExp(e->loc, e, new IntegerExp(1));
+            e = new PtrExp(e->loc, e);
+            e = ::semantic(e, sc);
+            return e;
+        }
+
+        if (ident == Id::outer && sym->vthis)
+        {
+            if (sym->vthis->_scope)
+                sym->vthis->semantic(NULL);
+
+            if (ClassDeclaration *cdp = sym->toParent2()->isClassDeclaration())
+            {
+                DotVarExp *dve = new DotVarExp(e->loc, e, sym->vthis);
+                dve->type = cdp->type->addMod(e->type->mod);
+                return dve;
+            }
+
+            /* Bugzilla 15839: Find closest parent class through nested functions.
+             */
+            for (Dsymbol *p = sym->toParent2(); p; p = p->toParent2())
+            {
+                FuncDeclaration *fd = p->isFuncDeclaration();
+                if (!fd)
+                    break;
+                if (fd->isNested())
+                    continue;
+                AggregateDeclaration *ad = fd->isThis();
+                if (!ad)
+                    break;
+                if (ClassDeclaration *cdp = ad->isClassDeclaration())
+                {
+                    ThisExp *ve = new ThisExp(e->loc);
+
+                    ve->var = fd->vthis;
+                    const bool nestedError = fd->vthis->checkNestedReference(sc, e->loc);
+                    assert(!nestedError);
+
+                    ve->type = fd->vthis->type->addMod(e->type->mod);
+                    return ve;
+                }
+                break;
+            }
+
+            // Continue to show enclosing function's frame (stack or closure).
+            DotVarExp *dve = new DotVarExp(e->loc, e, sym->vthis);
+            dve->type = sym->vthis->type->addMod(e->type->mod);
+            return dve;
+        }
+
+        return noMember(sc, e, ident, flag & 1);
+    }
+    if (!(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, s))
+    {
+        ::deprecation(e->loc, "%s is not visible from module %s", s->toPrettyChars(), sc->_module->toPrettyChars());
+        // return noMember(sc, e, ident, flag);
+    }
+    if (!s->isFuncDeclaration())        // because of overloading
+        s->checkDeprecated(e->loc, sc);
+    s = s->toAlias();
+
+    EnumMember *em = s->isEnumMember();
+    if (em)
+    {
+        return em->getVarExp(e->loc, sc);
+    }
+
+    if (VarDeclaration *v = s->isVarDeclaration())
+    {
+        if (!v->type ||
+            !v->type->deco && v->inuse)
+        {
+            if (v->inuse) // Bugzilla 9494
+                e->error("circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+            else
+                e->error("forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+            return new ErrorExp();
+        }
+        if (v->type->ty == Terror)
+            return new ErrorExp();
+
+        if ((v->storage_class & STCmanifest) && v->_init)
+        {
+            if (v->inuse)
+            {
+                e->error("circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+                return new ErrorExp();
+            }
+            checkAccess(e->loc, sc, NULL, v);
+            Expression *ve = new VarExp(e->loc, v);
+            ve = ::semantic(ve, sc);
+            return ve;
+        }
+    }
+
+    if (s->getType())
+    {
+        return new TypeExp(e->loc, s->getType());
+    }
+
+    TemplateMixin *tm = s->isTemplateMixin();
+    if (tm)
+    {
+        Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
+        de->type = e->type;
+        return de;
+    }
+
+    TemplateDeclaration *td = s->isTemplateDeclaration();
+    if (td)
+    {
+        if (e->op == TOKtype)
+            e = new ScopeExp(e->loc, td);
+        else
+            e = new DotTemplateExp(e->loc, e, td);
+        e = ::semantic(e, sc);
+        return e;
+    }
+
+    TemplateInstance *ti = s->isTemplateInstance();
+    if (ti)
+    {
+        if (!ti->semanticRun)
+        {
+            ti->semantic(sc);
+            if (!ti->inst || ti->errors)    // if template failed to expand
+                return new ErrorExp();
+        }
+        s = ti->inst->toAlias();
+        if (!s->isTemplateInstance())
+            goto L1;
+        if (e->op == TOKtype)
+            e = new ScopeExp(e->loc, ti);
+        else
+            e = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
+        return ::semantic(e, sc);
+    }
+
+    if (s->isImport() || s->isModule() || s->isPackage())
+    {
+        e = ::resolve(e->loc, sc, s, false);
+        return e;
+    }
+
+    OverloadSet *o = s->isOverloadSet();
+    if (o)
+    {
+        OverExp *oe = new OverExp(e->loc, o);
+        if (e->op == TOKtype)
+            return oe;
+        return new DotExp(e->loc, e, oe);
+    }
+
+    Declaration *d = s->isDeclaration();
+    if (!d)
+    {
+        e->error("%s.%s is not a declaration", e->toChars(), ident->toChars());
+        return new ErrorExp();
+    }
+
+    if (e->op == TOKtype)
+    {
+        /* It's:
+         *    Class.d
+         */
+        if (TupleDeclaration *tup = d->isTupleDeclaration())
+        {
+            e = new TupleExp(e->loc, tup);
+            e = ::semantic(e, sc);
+            return e;
+        }
+        if (d->needThis() && sc->intypeof != 1)
+        {
+            /* Rewrite as:
+             *  this.d
+             */
+            if (hasThis(sc))
+            {
+                // This is almost same as getRightThis() in expression.c
+                Expression *e1 = new ThisExp(e->loc);
+                e1 = ::semantic(e1, sc);
+            L2:
+                Type *t = e1->type->toBasetype();
+                ClassDeclaration *cd = e->type->isClassHandle();
+                ClassDeclaration *tcd = t->isClassHandle();
+                if (cd && tcd && (tcd == cd || cd->isBaseOf(tcd, NULL)))
+                {
+                    e = new DotTypeExp(e1->loc, e1, cd);
+                    e = new DotVarExp(e->loc, e, d);
+                    e = ::semantic(e, sc);
+                    return e;
+                }
+                if (tcd && tcd->isNested())
+                {   /* e1 is the 'this' pointer for an inner class: tcd.
+                     * Rewrite it as the 'this' pointer for the outer class.
+                     */
+
+                    e1 = new DotVarExp(e->loc, e1, tcd->vthis);
+                    e1->type = tcd->vthis->type;
+                    e1->type = e1->type->addMod(t->mod);
+                    // Do not call checkNestedRef()
+                    //e1 = ::semantic(e1, sc);
+
+                    // Skip up over nested functions, and get the enclosing
+                    // class type.
+                    int n = 0;
+                    for (s = tcd->toParent();
+                         s && s->isFuncDeclaration();
+                         s = s->toParent())
+                    {   FuncDeclaration *f = s->isFuncDeclaration();
+                        if (f->vthis)
+                        {
+                            //printf("rewriting e1 to %s's this\n", f->toChars());
+                            n++;
+                            e1 = new VarExp(e->loc, f->vthis);
+                        }
+                        else
+                        {
+                            e = new VarExp(e->loc, d);
+                            return e;
+                        }
+                    }
+                    if (s && s->isClassDeclaration())
+                    {   e1->type = s->isClassDeclaration()->type;
+                        e1->type = e1->type->addMod(t->mod);
+                        if (n > 1)
+                            e1 = ::semantic(e1, sc);
+                    }
+                    else
+                        e1 = ::semantic(e1, sc);
+                    goto L2;
+                }
+            }
+        }
+        //printf("e = %s, d = %s\n", e->toChars(), d->toChars());
+        if (d->semanticRun == PASSinit && d->_scope)
+            d->semantic(d->_scope);
+        checkAccess(e->loc, sc, e, d);
+        VarExp *ve = new VarExp(e->loc, d);
+        if (d->isVarDeclaration() && d->needThis())
+            ve->type = d->type->addMod(e->type->mod);
+        return ve;
+    }
+
+    bool unreal = e->op == TOKvar && ((VarExp *)e)->var->isField();
+    if (d->isDataseg() || unreal && d->isField())
+    {
+        // (e, d)
+        checkAccess(e->loc, sc, e, d);
+        Expression *ve = new VarExp(e->loc, d);
+        e = unreal ? ve : new CommaExp(e->loc, e, ve);
+        e = ::semantic(e, sc);
+        return e;
+    }
+
+    e = new DotVarExp(e->loc, e, d);
+    e = ::semantic(e, sc);
+    return e;
+}
+
+ClassDeclaration *TypeClass::isClassHandle()
+{
+    return sym;
+}
+
+bool TypeClass::isscope()
+{
+    return sym->isscope;
+}
+
+bool TypeClass::isBaseOf(Type *t, int *poffset)
+{
+    if (t && t->ty == Tclass)
+    {
+        ClassDeclaration *cd = ((TypeClass *)t)->sym;
+        if (sym->isBaseOf(cd, poffset))
+            return true;
+    }
+    return false;
+}
+
+MATCH TypeClass::implicitConvTo(Type *to)
+{
+    //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to->toChars(), toChars());
+    MATCH m = constConv(to);
+    if (m > MATCHnomatch)
+        return m;
+
+    ClassDeclaration *cdto = to->isClassHandle();
+    if (cdto)
+    {
+        //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to->toChars(), toChars(), cdto->isBaseInfoComplete(), sym->isBaseInfoComplete());
+        if (cdto->_scope && !cdto->isBaseInfoComplete())
+            cdto->semantic(NULL);
+        if (sym->_scope && !sym->isBaseInfoComplete())
+            sym->semantic(NULL);
+        if (cdto->isBaseOf(sym, NULL) && MODimplicitConv(mod, to->mod))
+        {
+            //printf("'to' is base\n");
+            return MATCHconvert;
+        }
+    }
+
+    m = MATCHnomatch;
+    if (sym->aliasthis && !(att & RECtracing))
+    {
+        att = (AliasThisRec)(att | RECtracing);
+        m = aliasthisOf()->implicitConvTo(to);
+        att = (AliasThisRec)(att & ~RECtracing);
+    }
+
+    return m;
+}
+
+MATCH TypeClass::constConv(Type *to)
+{
+    if (equals(to))
+        return MATCHexact;
+    if (ty == to->ty && sym == ((TypeClass *)to)->sym &&
+        MODimplicitConv(mod, to->mod))
+        return MATCHconst;
+
+    /* Conversion derived to const(base)
+     */
+    int offset = 0;
+    if (to->isBaseOf(this, &offset) && offset == 0 &&
+        MODimplicitConv(mod, to->mod))
+    {
+        // Disallow:
+        //  derived to base
+        //  inout(derived) to inout(base)
+        if (!to->isMutable() && !to->isWild())
+            return MATCHconvert;
+    }
+
+    return MATCHnomatch;
+}
+
+unsigned char TypeClass::deduceWild(Type *t, bool isRef)
+{
+    ClassDeclaration *cd = t->isClassHandle();
+    if (cd && (sym == cd || cd->isBaseOf(sym, NULL)))
+        return Type::deduceWild(t, isRef);
+
+    unsigned char wm = 0;
+
+    if (t->hasWild() && sym->aliasthis && !(att & RECtracing))
+    {
+        att = (AliasThisRec)(att | RECtracing);
+        wm = aliasthisOf()->deduceWild(t, isRef);
+        att = (AliasThisRec)(att & ~RECtracing);
+    }
+
+    return wm;
+}
+
+Type *TypeClass::toHeadMutable()
+{
+    return this;
+}
+
+Expression *TypeClass::defaultInit(Loc loc)
+{
+#if LOGDEFAULTINIT
+    printf("TypeClass::defaultInit() '%s'\n", toChars());
+#endif
+    return new NullExp(loc, this);
+}
+
+bool TypeClass::isZeroInit(Loc loc)
+{
+    return true;
+}
+
+bool TypeClass::isBoolean()
+{
+    return true;
+}
+
+bool TypeClass::hasPointers()
+{
+    return true;
+}
+
+/***************************** TypeTuple *****************************/
+
+TypeTuple::TypeTuple(Parameters *arguments)
+    : Type(Ttuple)
+{
+    //printf("TypeTuple(this = %p)\n", this);
+    this->arguments = arguments;
+    //printf("TypeTuple() %p, %s\n", this, toChars());
+#ifdef DEBUG
+    if (arguments)
+    {
+        for (size_t i = 0; i < arguments->dim; i++)
+        {
+            Parameter *arg = (*arguments)[i];
+            assert(arg && arg->type);
+        }
+    }
+#endif
+}
+
+/****************
+ * Form TypeTuple from the types of the expressions.
+ * Assume exps[] is already tuple expanded.
+ */
+
+TypeTuple::TypeTuple(Expressions *exps)
+    : Type(Ttuple)
+{
+    Parameters *arguments = new Parameters;
+    if (exps)
+    {
+        arguments->setDim(exps->dim);
+        for (size_t i = 0; i < exps->dim; i++)
+        {   Expression *e = (*exps)[i];
+            if (e->type->ty == Ttuple)
+                e->error("cannot form tuple of tuples");
+            Parameter *arg = new Parameter(STCundefined, e->type, NULL, NULL);
+            (*arguments)[i] = arg;
+        }
+    }
+    this->arguments = arguments;
+    //printf("TypeTuple() %p, %s\n", this, toChars());
+}
+
+TypeTuple *TypeTuple::create(Parameters *arguments)
+{
+    return new TypeTuple(arguments);
+}
+
+/*******************************************
+ * Type tuple with 0, 1 or 2 types in it.
+ */
+TypeTuple::TypeTuple()
+    : Type(Ttuple)
+{
+    arguments = new Parameters();
+}
+
+TypeTuple::TypeTuple(Type *t1)
+    : Type(Ttuple)
+{
+    arguments = new Parameters();
+    arguments->push(new Parameter(0, t1, NULL, NULL));
+}
+
+TypeTuple::TypeTuple(Type *t1, Type *t2)
+    : Type(Ttuple)
+{
+    arguments = new Parameters();
+    arguments->push(new Parameter(0, t1, NULL, NULL));
+    arguments->push(new Parameter(0, t2, NULL, NULL));
+}
+
+const char *TypeTuple::kind()
+{
+    return "tuple";
+}
+
+Type *TypeTuple::syntaxCopy()
+{
+    Parameters *args = Parameter::arraySyntaxCopy(arguments);
+    Type *t = new TypeTuple(args);
+    t->mod = mod;
+    return t;
+}
+
+Type *TypeTuple::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeTuple::semantic(this = %p)\n", this);
+    //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
+    if (!deco)
+        deco = merge()->deco;
+
+    /* Don't return merge(), because a tuple with one type has the
+     * same deco as that type.
+     */
+    return this;
+}
+
+bool TypeTuple::equals(RootObject *o)
+{
+    Type *t = (Type *)o;
+    //printf("TypeTuple::equals(%s, %s)\n", toChars(), t->toChars());
+    if (this == t)
+        return true;
+    if (t->ty == Ttuple)
+    {
+        TypeTuple *tt = (TypeTuple *)t;
+        if (arguments->dim == tt->arguments->dim)
+        {
+            for (size_t i = 0; i < tt->arguments->dim; i++)
+            {
+                Parameter *arg1 = (*arguments)[i];
+                Parameter *arg2 = (*tt->arguments)[i];
+                if (!arg1->type->equals(arg2->type))
+                    return false;
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+#if 0
+Type *TypeTuple::makeConst()
+{
+    //printf("TypeTuple::makeConst() %s\n", toChars());
+    if (cto)
+        return cto;
+    TypeTuple *t = (TypeTuple *)Type::makeConst();
+    t->arguments = new Parameters();
+    t->arguments->setDim(arguments->dim);
+    for (size_t i = 0; i < arguments->dim; i++)
+    {   Parameter *arg = (*arguments)[i];
+        Parameter *narg = new Parameter(arg->storageClass, arg->type->constOf(), arg->ident, arg->defaultArg);
+        (*t->arguments)[i] = (Parameter *)narg;
+    }
+    return t;
+}
+#endif
+
+Expression *TypeTuple::getProperty(Loc loc, Identifier *ident, int flag)
+{   Expression *e;
+
+#if LOGDOTEXP
+    printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars());
+#endif
+    if (ident == Id::length)
+    {
+        e = new IntegerExp(loc, arguments->dim, Type::tsize_t);
+    }
+    else if (ident == Id::_init)
+    {
+        e = defaultInitLiteral(loc);
+    }
+    else if (flag)
+    {
+        e = NULL;
+    }
+    else
+    {
+        error(loc, "no property '%s' for tuple '%s'", ident->toChars(), toChars());
+        e = new ErrorExp();
+    }
+    return e;
+}
+
+Expression *TypeTuple::defaultInit(Loc loc)
+{
+    Expressions *exps = new Expressions();
+    exps->setDim(arguments->dim);
+    for (size_t i = 0; i < arguments->dim; i++)
+    {
+        Parameter *p = (*arguments)[i];
+        assert(p->type);
+        Expression *e = p->type->defaultInitLiteral(loc);
+        if (e->op == TOKerror)
+            return e;
+        (*exps)[i] = e;
+    }
+    return new TupleExp(loc, exps);
+}
+
+/***************************** TypeSlice *****************************/
+
+/* This is so we can slice a TypeTuple */
+
+TypeSlice::TypeSlice(Type *next, Expression *lwr, Expression *upr)
+    : TypeNext(Tslice, next)
+{
+    //printf("TypeSlice[%s .. %s]\n", lwr->toChars(), upr->toChars());
+    this->lwr = lwr;
+    this->upr = upr;
+}
+
+const char *TypeSlice::kind()
+{
+    return "slice";
+}
+
+Type *TypeSlice::syntaxCopy()
+{
+    Type *t = new TypeSlice(next->syntaxCopy(), lwr->syntaxCopy(), upr->syntaxCopy());
+    t->mod = mod;
+    return t;
+}
+
+Type *TypeSlice::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeSlice::semantic() %s\n", toChars());
+    Type *tn = next->semantic(loc, sc);
+    //printf("next: %s\n", tn->toChars());
+
+    Type *tbn = tn->toBasetype();
+    if (tbn->ty != Ttuple)
+    {
+        error(loc, "can only slice tuple types, not %s", tbn->toChars());
+        return Type::terror;
+    }
+    TypeTuple *tt = (TypeTuple *)tbn;
+
+    lwr = semanticLength(sc, tbn, lwr);
+    lwr = lwr->ctfeInterpret();
+    uinteger_t i1 = lwr->toUInteger();
+
+    upr = semanticLength(sc, tbn, upr);
+    upr = upr->ctfeInterpret();
+    uinteger_t i2 = upr->toUInteger();
+
+    if (!(i1 <= i2 && i2 <= tt->arguments->dim))
+    {
+        error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, tt->arguments->dim);
+        return Type::terror;
+    }
+
+    next = tn;
+    transitive();
+
+    Parameters *args = new Parameters;
+    args->reserve((size_t)(i2 - i1));
+    for (size_t i = (size_t)i1; i < (size_t)i2; i++)
+    {
+        Parameter *arg = (*tt->arguments)[i];
+        args->push(arg);
+    }
+    Type *t = new TypeTuple(args);
+    return t->semantic(loc, sc);
+}
+
+void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+    next->resolve(loc, sc, pe, pt, ps, intypeid);
+    if (*pe)
+    {
+        // It's really a slice expression
+        if (Dsymbol *s = getDsymbol(*pe))
+            *pe = new DsymbolExp(loc, s);
+        *pe = new ArrayExp(loc, *pe, new IntervalExp(loc, lwr, upr));
+    }
+    else if (*ps)
+    {
+        Dsymbol *s = *ps;
+        TupleDeclaration *td = s->isTupleDeclaration();
+        if (td)
+        {
+            /* It's a slice of a TupleDeclaration
+             */
+            ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
+            sym->parent = sc->scopesym;
+            sc = sc->push(sym);
+            sc = sc->startCTFE();
+            lwr = ::semantic(lwr, sc);
+            upr = ::semantic(upr, sc);
+            sc = sc->endCTFE();
+            sc = sc->pop();
+
+            lwr = lwr->ctfeInterpret();
+            upr = upr->ctfeInterpret();
+            uinteger_t i1 = lwr->toUInteger();
+            uinteger_t i2 = upr->toUInteger();
+
+            if (!(i1 <= i2 && i2 <= td->objects->dim))
+            {
+                error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, td->objects->dim);
+                goto Ldefault;
+            }
+
+            if (i1 == 0 && i2 == td->objects->dim)
+            {
+                *ps = td;
+                return;
+            }
+
+            /* Create a new TupleDeclaration which
+             * is a slice [i1..i2] out of the old one.
+             */
+            Objects *objects = new Objects;
+            objects->setDim((size_t)(i2 - i1));
+            for (size_t i = 0; i < objects->dim; i++)
+            {
+                (*objects)[i] = (*td->objects)[(size_t)i1 + i];
+            }
+
+            TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
+            *ps = tds;
+        }
+        else
+            goto Ldefault;
+    }
+    else
+    {
+        if ((*pt)->ty != Terror)
+            next = *pt;     // prevent re-running semantic() on 'next'
+     Ldefault:
+        Type::resolve(loc, sc, pe, pt, ps, intypeid);
+    }
+}
+
+/***************************** TypeNull *****************************/
+
+TypeNull::TypeNull()
+        : Type(Tnull)
+{
+}
+
+const char *TypeNull::kind()
+{
+    return "null";
+}
+
+Type *TypeNull::syntaxCopy()
+{
+    // No semantic analysis done, no need to copy
+    return this;
+}
+
+MATCH TypeNull::implicitConvTo(Type *to)
+{
+    //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to);
+    //printf("from: %s\n", toChars());
+    //printf("to  : %s\n", to->toChars());
+    MATCH m = Type::implicitConvTo(to);
+    if (m != MATCHnomatch)
+        return m;
+
+    // NULL implicitly converts to any pointer type or dynamic array
+    //if (type->ty == Tpointer && type->nextOf()->ty == Tvoid)
+    {
+        Type *tb = to->toBasetype();
+        if (tb->ty == Tnull ||
+            tb->ty == Tpointer || tb->ty == Tarray ||
+            tb->ty == Taarray  || tb->ty == Tclass ||
+            tb->ty == Tdelegate)
+            return MATCHconst;
+    }
+
+    return MATCHnomatch;
+}
+
+bool TypeNull::isBoolean()
+{
+    return true;
+}
+
+d_uns64 TypeNull::size(Loc loc) { return tvoidptr->size(loc); }
+Expression *TypeNull::defaultInit(Loc loc) { return new NullExp(Loc(), Type::tnull); }
+
+/***************************** Parameter *****************************/
+
+Parameter::Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg)
+{
+    this->type = type;
+    this->ident = ident;
+    this->storageClass = storageClass;
+    this->defaultArg = defaultArg;
+}
+
+Parameter *Parameter::create(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg)
+{
+    return new Parameter(storageClass, type, ident, defaultArg);
+}
+
+Parameter *Parameter::syntaxCopy()
+{
+    return new Parameter(storageClass,
+        type ? type->syntaxCopy() : NULL,
+        ident,
+        defaultArg ? defaultArg->syntaxCopy() : NULL);
+}
+
+Parameters *Parameter::arraySyntaxCopy(Parameters *parameters)
+{
+    Parameters *params = NULL;
+    if (parameters)
+    {
+        params = new Parameters();
+        params->setDim(parameters->dim);
+        for (size_t i = 0; i < params->dim; i++)
+            (*params)[i] = (*parameters)[i]->syntaxCopy();
+    }
+    return params;
+}
+
+/****************************************
+ * Determine if parameter list is really a template parameter list
+ * (i.e. it has auto or alias parameters)
+ */
+
+static int isTPLDg(void *ctx, size_t n, Parameter *p)
+{
+    if (p->storageClass & (STCalias | STCauto | STCstatic))
+        return 1;
+    return 0;
+}
+
+/****************************************************
+ * Determine if parameter is a lazy array of delegates.
+ * If so, return the return type of those delegates.
+ * If not, return NULL.
+ *
+ * Returns T if the type is one of the following forms:
+ *      T delegate()[]
+ *      T delegate()[dim]
+ */
+
+Type *Parameter::isLazyArray()
+{
+    Type *tb = type->toBasetype();
+    if (tb->ty == Tsarray || tb->ty == Tarray)
+    {
+        Type *tel = ((TypeArray *)tb)->next->toBasetype();
+        if (tel->ty == Tdelegate)
+        {
+            TypeDelegate *td = (TypeDelegate *)tel;
+            TypeFunction *tf = (TypeFunction *)td->next;
+
+            if (!tf->varargs && Parameter::dim(tf->parameters) == 0)
+            {
+                return tf->next;    // return type of delegate
+            }
+        }
+    }
+    return NULL;
+}
+
+/***************************************
+ * Determine number of arguments, folding in tuples.
+ */
+
+static int dimDg(void *ctx, size_t n, Parameter *)
+{
+    ++*(size_t *)ctx;
+    return 0;
+}
+
+size_t Parameter::dim(Parameters *parameters)
+{
+    size_t n = 0;
+    Parameter_foreach(parameters, &dimDg, &n);
+    return n;
+}
+
+/***************************************
+ * Get nth Parameter, folding in tuples.
+ * Returns:
+ *      Parameter*      nth Parameter
+ *      NULL            not found, *pn gets incremented by the number
+ *                      of Parameters
+ */
+
+struct GetNthParamCtx
+{
+    size_t nth;
+    Parameter *param;
+};
+
+static int getNthParamDg(void *ctx, size_t n, Parameter *p)
+{
+    GetNthParamCtx *c = (GetNthParamCtx *)ctx;
+    if (n == c->nth)
+    {
+        c->param = p;
+        return 1;
+    }
+    return 0;
+}
+
+Parameter *Parameter::getNth(Parameters *parameters, size_t nth, size_t *pn)
+{
+    GetNthParamCtx ctx = { nth, NULL };
+    int res = Parameter_foreach(parameters, &getNthParamDg, &ctx);
+    return res ? ctx.param : NULL;
+}
+
+/***************************************
+ * Expands tuples in args in depth first order. Calls
+ * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter.
+ * If dg returns !=0, stops and returns that value else returns 0.
+ * Use this function to avoid the O(N + N^2/2) complexity of
+ * calculating dim and calling N times getNth.
+ */
+
+int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn)
+{
+    assert(dg);
+    if (!parameters)
+        return 0;
+
+    size_t n = pn ? *pn : 0; // take over index
+    int result = 0;
+    for (size_t i = 0; i < parameters->dim; i++)
+    {
+        Parameter *p = (*parameters)[i];
+        Type *t = p->type->toBasetype();
+
+        if (t->ty == Ttuple)
+        {
+            TypeTuple *tu = (TypeTuple *)t;
+            result = Parameter_foreach(tu->arguments, dg, ctx, &n);
+        }
+        else
+            result = dg(ctx, n++, p);
+
+        if (result)
+            break;
+    }
+
+    if (pn)
+        *pn = n; // update index
+    return result;
+}
+
+
+const char *Parameter::toChars()
+{
+    return ident ? ident->toChars() : "__anonymous_param";
+}
+
+/*********************************
+ * Compute covariance of parameters `this` and `p`
+ * as determined by the storage classes of both.
+ * Params:
+ *  p = Parameter to compare with
+ * Returns:
+ *  true = `this` can be used in place of `p`
+ *  false = nope
+ */
+bool Parameter::isCovariant(bool returnByRef, const Parameter *p) const
+{
+    const StorageClass stc = STCref | STCin | STCout | STClazy;
+    if ((this->storageClass & stc) != (p->storageClass & stc))
+        return false;
+
+    return isCovariantScope(returnByRef, this->storageClass, p->storageClass);
+}
+
+bool Parameter::isCovariantScope(bool returnByRef, StorageClass from, StorageClass to)
+{
+    if (from == to)
+        return true;
+
+    struct SR
+    {
+        /* Classification of 'scope-return-ref' possibilities
+        */
+        enum
+        {
+            SRNone,
+            SRScope,
+            SRReturnScope,
+            SRRef,
+            SRReturnRef,
+            SRRefScope,
+            SRReturnRef_Scope,
+            SRRef_ReturnScope,
+            SRMAX,
+        };
+
+        /* Shrinking the representation is necessary because StorageClass is so wide
+         * Params:
+         *   returnByRef = true if the function returns by ref
+         *   stc = storage class of parameter
+         */
+        static unsigned buildSR(bool returnByRef, StorageClass stc)
+        {
+            unsigned result;
+            switch (stc & (STCref | STCscope | STCreturn))
+            {
+                case 0:                    result = SRNone;        break;
+                case STCref:               result = SRRef;         break;
+                case STCscope:             result = SRScope;       break;
+                case STCreturn | STCref:   result = SRReturnRef;   break;
+                case STCreturn | STCscope: result = SRReturnScope; break;
+                case STCref    | STCscope: result = SRRefScope;    break;
+                case STCreturn | STCref | STCscope:
+                    result = returnByRef ? SRReturnRef_Scope : SRRef_ReturnScope;
+                    break;
+                default:
+                    assert(0);
+            }
+            return result;
+        }
+
+        static void covariantInit(bool covariant[SRMAX][SRMAX])
+        {
+            /* Initialize covariant[][] with this:
+
+                 From\To           n   rs  s
+                 None              X
+                 ReturnScope       X   X
+                 Scope             X   X   X
+
+                 From\To           r   rr  rs  rr-s r-rs
+                 Ref               X   X
+                 ReturnRef             X
+                 RefScope          X   X   X   X    X
+                 ReturnRef-Scope       X       X
+                 Ref-ReturnScope   X   X            X
+            */
+            for (int i = 0; i < SRMAX; i++)
+            {
+                covariant[i][i] = true;
+                covariant[SRRefScope][i] = true;
+            }
+            covariant[SRReturnScope][SRNone]        = true;
+            covariant[SRScope      ][SRNone]        = true;
+            covariant[SRScope      ][SRReturnScope] = true;
+
+            covariant[SRRef            ][SRReturnRef] = true;
+            covariant[SRReturnRef_Scope][SRReturnRef] = true;
+            covariant[SRRef_ReturnScope][SRRef      ] = true;
+            covariant[SRRef_ReturnScope][SRReturnRef] = true;
+        }
+    };
+
+    /* result is true if the 'from' can be used as a 'to'
+     */
+
+    if ((from ^ to) & STCref)               // differing in 'ref' means no covariance
+        return false;
+
+    static bool covariant[SR::SRMAX][SR::SRMAX];
+    static bool init = false;
+    if (!init)
+    {
+        SR::covariantInit(covariant);
+        init = true;
+    }
+
+    return covariant[SR::buildSR(returnByRef, from)][SR::buildSR(returnByRef, to)];
+}
diff --git a/gcc/d/dfrontend/mtype.h b/gcc/d/dfrontend/mtype.h
new file mode 100644
index 00000000000..80570e5ffda
--- /dev/null
+++ b/gcc/d/dfrontend/mtype.h
@@ -0,0 +1,942 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/mtype.h
+ */
+
+#ifndef DMD_MTYPE_H
+#define DMD_MTYPE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "stringtable.h"
+#include "rmem.h" // for d_size_t
+
+#include "arraytypes.h"
+#include "expression.h"
+#include "visitor.h"
+
+struct Scope;
+class Identifier;
+class Expression;
+class StructDeclaration;
+class ClassDeclaration;
+class EnumDeclaration;
+class TypeInfoDeclaration;
+class Dsymbol;
+class TemplateInstance;
+class TemplateDeclaration;
+enum LINK;
+
+class TypeBasic;
+class Parameter;
+
+// Back end
+#ifdef IN_GCC
+typedef union tree_node type;
+#else
+typedef struct TYPE type;
+#endif
+
+void semanticTypeInfo(Scope *sc, Type *t);
+MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wm = NULL, size_t inferStart = 0);
+StorageClass ModToStc(unsigned mod);
+
+enum ENUMTY
+{
+    Tarray,             // slice array, aka T[]
+    Tsarray,            // static array, aka T[dimension]
+    Taarray,            // associative array, aka T[type]
+    Tpointer,
+    Treference,
+    Tfunction,
+    Tident,
+    Tclass,
+    Tstruct,
+    Tenum,
+
+    Tdelegate,
+    Tnone,
+    Tvoid,
+    Tint8,
+    Tuns8,
+    Tint16,
+    Tuns16,
+    Tint32,
+    Tuns32,
+    Tint64,
+
+    Tuns64,
+    Tfloat32,
+    Tfloat64,
+    Tfloat80,
+    Timaginary32,
+    Timaginary64,
+    Timaginary80,
+    Tcomplex32,
+    Tcomplex64,
+    Tcomplex80,
+
+    Tbool,
+    Tchar,
+    Twchar,
+    Tdchar,
+    Terror,
+    Tinstance,
+    Ttypeof,
+    Ttuple,
+    Tslice,
+    Treturn,
+
+    Tnull,
+    Tvector,
+    Tint128,
+    Tuns128,
+    TMAX
+};
+typedef unsigned char TY;       // ENUMTY
+
+extern int Tsize_t;
+extern int Tptrdiff_t;
+
+#define SIZE_INVALID (~(d_uns64)0)   // error return from size() functions
+
+
+/**
+ * type modifiers
+ * pick this order of numbers so switch statements work better
+ */
+enum MODFlags
+{
+    MODconst     = 1, // type is const
+    MODimmutable = 4, // type is immutable
+    MODshared    = 2, // type is shared
+    MODwild      = 8, // type is wild
+    MODwildconst = (MODwild | MODconst), // type is wild const
+    MODmutable   = 0x10       // type is mutable (only used in wildcard matching)
+};
+typedef unsigned char MOD;
+
+// These tables are for implicit conversion of binary ops;
+// the indices are the type of operand one, followed by operand two.
+extern unsigned char impcnvResult[TMAX][TMAX];
+extern unsigned char impcnvType1[TMAX][TMAX];
+extern unsigned char impcnvType2[TMAX][TMAX];
+
+// If !=0, give warning on implicit conversion
+extern unsigned char impcnvWarn[TMAX][TMAX];
+
+class Type : public RootObject
+{
+public:
+    TY ty;
+    MOD mod;  // modifiers MODxxxx
+    char *deco;
+
+    /* These are cached values that are lazily evaluated by constOf(), immutableOf(), etc.
+     * They should not be referenced by anybody but mtype.c.
+     * They can be NULL if not lazily evaluated yet.
+     * Note that there is no "shared immutable", because that is just immutable
+     * Naked == no MOD bits
+     */
+
+    Type *cto;          // MODconst                 ? naked version of this type : const version
+    Type *ito;          // MODimmutable             ? naked version of this type : immutable version
+    Type *sto;          // MODshared                ? naked version of this type : shared mutable version
+    Type *scto;         // MODshared | MODconst     ? naked version of this type : shared const version
+    Type *wto;          // MODwild                  ? naked version of this type : wild version
+    Type *wcto;         // MODwildconst             ? naked version of this type : wild const version
+    Type *swto;         // MODshared | MODwild      ? naked version of this type : shared wild version
+    Type *swcto;        // MODshared | MODwildconst ? naked version of this type : shared wild const version
+
+    Type *pto;          // merged pointer to this type
+    Type *rto;          // reference to this type
+    Type *arrayof;      // array of this type
+    TypeInfoDeclaration *vtinfo;        // TypeInfo object for this Type
+
+    type *ctype;        // for back end
+
+    static Type *tvoid;
+    static Type *tint8;
+    static Type *tuns8;
+    static Type *tint16;
+    static Type *tuns16;
+    static Type *tint32;
+    static Type *tuns32;
+    static Type *tint64;
+    static Type *tuns64;
+    static Type *tint128;
+    static Type *tuns128;
+    static Type *tfloat32;
+    static Type *tfloat64;
+    static Type *tfloat80;
+
+    static Type *timaginary32;
+    static Type *timaginary64;
+    static Type *timaginary80;
+
+    static Type *tcomplex32;
+    static Type *tcomplex64;
+    static Type *tcomplex80;
+
+    static Type *tbool;
+    static Type *tchar;
+    static Type *twchar;
+    static Type *tdchar;
+
+    // Some special types
+    static Type *tshiftcnt;
+    static Type *tvoidptr;              // void*
+    static Type *tstring;               // immutable(char)[]
+    static Type *twstring;              // immutable(wchar)[]
+    static Type *tdstring;              // immutable(dchar)[]
+    static Type *tvalist;               // va_list alias
+    static Type *terror;                // for error recovery
+    static Type *tnull;                 // for null type
+
+    static Type *tsize_t;               // matches size_t alias
+    static Type *tptrdiff_t;            // matches ptrdiff_t alias
+    static Type *thash_t;               // matches hash_t alias
+
+    static ClassDeclaration *dtypeinfo;
+    static ClassDeclaration *typeinfoclass;
+    static ClassDeclaration *typeinfointerface;
+    static ClassDeclaration *typeinfostruct;
+    static ClassDeclaration *typeinfopointer;
+    static ClassDeclaration *typeinfoarray;
+    static ClassDeclaration *typeinfostaticarray;
+    static ClassDeclaration *typeinfoassociativearray;
+    static ClassDeclaration *typeinfovector;
+    static ClassDeclaration *typeinfoenum;
+    static ClassDeclaration *typeinfofunction;
+    static ClassDeclaration *typeinfodelegate;
+    static ClassDeclaration *typeinfotypelist;
+    static ClassDeclaration *typeinfoconst;
+    static ClassDeclaration *typeinfoinvariant;
+    static ClassDeclaration *typeinfoshared;
+    static ClassDeclaration *typeinfowild;
+
+    static TemplateDeclaration *rtinfo;
+
+    static Type *basic[TMAX];
+    static unsigned char sizeTy[TMAX];
+    static StringTable stringtable;
+
+    Type(TY ty);
+    virtual const char *kind();
+    Type *copy();
+    virtual Type *syntaxCopy();
+    bool equals(RootObject *o);
+    bool equivalent(Type *t);
+    // kludge for template.isType()
+    int dyncast() const { return DYNCAST_TYPE; }
+    int covariant(Type *t, StorageClass *pstc = NULL, bool fix17349 = true);
+    const char *toChars();
+    char *toPrettyChars(bool QualifyTypes = false);
+    static void _init();
+
+    d_uns64 size();
+    virtual d_uns64 size(Loc loc);
+    virtual unsigned alignsize();
+    virtual Type *semantic(Loc loc, Scope *sc);
+    Type *trySemantic(Loc loc, Scope *sc);
+    Type *merge();
+    Type *merge2();
+    void modToBuffer(OutBuffer *buf);
+    char *modToChars();
+
+    /** For each active modifier (MODconst, MODimmutable, etc) call fp with a
+    void* for the work param and a string representation of the attribute. */
+    int modifiersApply(void *param, int (*fp)(void *, const char *));
+
+    virtual bool isintegral();
+    virtual bool isfloating();   // real, imaginary, or complex
+    virtual bool isreal();
+    virtual bool isimaginary();
+    virtual bool iscomplex();
+    virtual bool isscalar();
+    virtual bool isunsigned();
+    virtual bool isscope();
+    virtual bool isString();
+    virtual bool isAssignable();
+    virtual bool isBoolean();
+    virtual void checkDeprecated(Loc loc, Scope *sc);
+    bool isConst() const       { return (mod & MODconst) != 0; }
+    bool isImmutable() const   { return (mod & MODimmutable) != 0; }
+    bool isMutable() const     { return (mod & (MODconst | MODimmutable | MODwild)) == 0; }
+    bool isShared() const      { return (mod & MODshared) != 0; }
+    bool isSharedConst() const { return (mod & (MODshared | MODconst)) == (MODshared | MODconst); }
+    bool isWild() const        { return (mod & MODwild) != 0; }
+    bool isWildConst() const   { return (mod & MODwildconst) == MODwildconst; }
+    bool isSharedWild() const  { return (mod & (MODshared | MODwild)) == (MODshared | MODwild); }
+    bool isNaked() const       { return mod == 0; }
+    Type *nullAttributes();
+    Type *constOf();
+    Type *immutableOf();
+    Type *mutableOf();
+    Type *sharedOf();
+    Type *sharedConstOf();
+    Type *unSharedOf();
+    Type *wildOf();
+    Type *wildConstOf();
+    Type *sharedWildOf();
+    Type *sharedWildConstOf();
+    void fixTo(Type *t);
+    void check();
+    Type *addSTC(StorageClass stc);
+    Type *castMod(MOD mod);
+    Type *addMod(MOD mod);
+    virtual Type *addStorageClass(StorageClass stc);
+    Type *pointerTo();
+    Type *referenceTo();
+    Type *arrayOf();
+    Type *sarrayOf(dinteger_t dim);
+    Type *aliasthisOf();
+    bool checkAliasThisRec();
+    virtual Type *makeConst();
+    virtual Type *makeImmutable();
+    virtual Type *makeShared();
+    virtual Type *makeSharedConst();
+    virtual Type *makeWild();
+    virtual Type *makeWildConst();
+    virtual Type *makeSharedWild();
+    virtual Type *makeSharedWildConst();
+    virtual Type *makeMutable();
+    virtual Dsymbol *toDsymbol(Scope *sc);
+    virtual Type *toBasetype();
+    virtual bool isBaseOf(Type *t, int *poffset);
+    virtual MATCH implicitConvTo(Type *to);
+    virtual MATCH constConv(Type *to);
+    virtual unsigned char deduceWild(Type *t, bool isRef);
+    virtual Type *substWildTo(unsigned mod);
+
+    Type *unqualify(unsigned m);
+
+    virtual Type *toHeadMutable();
+    virtual ClassDeclaration *isClassHandle();
+    virtual Expression *getProperty(Loc loc, Identifier *ident, int flag);
+    virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    virtual structalign_t alignment();
+    Expression *noMember(Scope *sc, Expression *e, Identifier *ident, int flag);
+    virtual Expression *defaultInit(Loc loc = Loc());
+    virtual Expression *defaultInitLiteral(Loc loc);
+    virtual bool isZeroInit(Loc loc = Loc());                // if initializer is 0
+    Identifier *getTypeInfoIdent();
+    virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+    void resolveExp(Expression *e, Type **pt, Expression **pe, Dsymbol **ps);
+    virtual int hasWild() const;
+    virtual bool hasPointers();
+    virtual bool hasVoidInitPointers();
+    virtual Type *nextOf();
+    Type *baseElemOf();
+    uinteger_t sizemask();
+    virtual bool needsDestruction();
+    virtual bool needsNested();
+    void checkComplexTransition(Loc loc);
+
+    static void error(Loc loc, const char *format, ...);
+    static void warning(Loc loc, const char *format, ...);
+
+    // For eliminating dynamic_cast
+    virtual TypeBasic *isTypeBasic();
+    virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeError : public Type
+{
+public:
+    TypeError();
+    Type *syntaxCopy();
+
+    d_uns64 size(Loc loc);
+    Expression *getProperty(Loc loc, Identifier *ident, int flag);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    Expression *defaultInit(Loc loc);
+    Expression *defaultInitLiteral(Loc loc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeNext : public Type
+{
+public:
+    Type *next;
+
+    TypeNext(TY ty, Type *next);
+    void checkDeprecated(Loc loc, Scope *sc);
+    int hasWild() const;
+    Type *nextOf();
+    Type *makeConst();
+    Type *makeImmutable();
+    Type *makeShared();
+    Type *makeSharedConst();
+    Type *makeWild();
+    Type *makeWildConst();
+    Type *makeSharedWild();
+    Type *makeSharedWildConst();
+    Type *makeMutable();
+    MATCH constConv(Type *to);
+    unsigned char deduceWild(Type *t, bool isRef);
+    void transitive();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeBasic : public Type
+{
+public:
+    const char *dstring;
+    unsigned flags;
+
+    TypeBasic(TY ty);
+    const char *kind();
+    Type *syntaxCopy();
+    d_uns64 size(Loc loc) /*const*/;
+    unsigned alignsize();
+    Expression *getProperty(Loc loc, Identifier *ident, int flag);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    bool isintegral();
+    bool isfloating() /*const*/;
+    bool isreal() /*const*/;
+    bool isimaginary() /*const*/;
+    bool iscomplex() /*const*/;
+    bool isscalar() /*const*/;
+    bool isunsigned() /*const*/;
+    MATCH implicitConvTo(Type *to);
+    Expression *defaultInit(Loc loc);
+    bool isZeroInit(Loc loc) /*const*/;
+
+    // For eliminating dynamic_cast
+    TypeBasic *isTypeBasic();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeVector : public Type
+{
+public:
+    Type *basetype;
+
+    TypeVector(Loc loc, Type *basetype);
+    static TypeVector *create(Loc loc, Type *basetype);
+    const char *kind();
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    d_uns64 size(Loc loc);
+    unsigned alignsize();
+    Expression *getProperty(Loc loc, Identifier *ident, int flag);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    bool isintegral();
+    bool isfloating();
+    bool isscalar();
+    bool isunsigned();
+    bool isBoolean() /*const*/;
+    MATCH implicitConvTo(Type *to);
+    Expression *defaultInit(Loc loc);
+    Expression *defaultInitLiteral(Loc loc);
+    TypeBasic *elementType();
+    bool isZeroInit(Loc loc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeArray : public TypeNext
+{
+public:
+    TypeArray(TY ty, Type *next);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// Static array, one with a fixed dimension
+class TypeSArray : public TypeArray
+{
+public:
+    Expression *dim;
+
+    TypeSArray(Type *t, Expression *dim);
+    const char *kind();
+    Type *syntaxCopy();
+    d_uns64 size(Loc loc);
+    unsigned alignsize();
+    Type *semantic(Loc loc, Scope *sc);
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    bool isString();
+    bool isZeroInit(Loc loc);
+    structalign_t alignment();
+    MATCH constConv(Type *to);
+    MATCH implicitConvTo(Type *to);
+    Expression *defaultInit(Loc loc);
+    Expression *defaultInitLiteral(Loc loc);
+    bool hasPointers();
+    bool needsDestruction();
+    bool needsNested();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// Dynamic array, no dimension
+class TypeDArray : public TypeArray
+{
+public:
+    TypeDArray(Type *t);
+    const char *kind();
+    Type *syntaxCopy();
+    d_uns64 size(Loc loc) /*const*/;
+    unsigned alignsize() /*const*/;
+    Type *semantic(Loc loc, Scope *sc);
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    bool isString();
+    bool isZeroInit(Loc loc) /*const*/;
+    bool isBoolean() /*const*/;
+    MATCH implicitConvTo(Type *to);
+    Expression *defaultInit(Loc loc);
+    bool hasPointers() /*const*/;
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeAArray : public TypeArray
+{
+public:
+    Type *index;                // key type
+    Loc loc;
+    Scope *sc;
+
+    TypeAArray(Type *t, Type *index);
+    static TypeAArray *create(Type *t, Type *index);
+    const char *kind();
+    Type *syntaxCopy();
+    d_uns64 size(Loc loc);
+    Type *semantic(Loc loc, Scope *sc);
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    Expression *defaultInit(Loc loc);
+    bool isZeroInit(Loc loc) /*const*/;
+    bool isBoolean() /*const*/;
+    bool hasPointers() /*const*/;
+    MATCH implicitConvTo(Type *to);
+    MATCH constConv(Type *to);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypePointer : public TypeNext
+{
+public:
+    TypePointer(Type *t);
+    static TypePointer *create(Type *t);
+    const char *kind();
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    d_uns64 size(Loc loc) /*const*/;
+    MATCH implicitConvTo(Type *to);
+    MATCH constConv(Type *to);
+    bool isscalar() /*const*/;
+    Expression *defaultInit(Loc loc);
+    bool isZeroInit(Loc loc) /*const*/;
+    bool hasPointers() /*const*/;
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeReference : public TypeNext
+{
+public:
+    TypeReference(Type *t);
+    const char *kind();
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    d_uns64 size(Loc loc) /*const*/;
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    Expression *defaultInit(Loc loc);
+    bool isZeroInit(Loc loc) /*const*/;
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+enum RET
+{
+    RETregs     = 1,    // returned in registers
+    RETstack    = 2,    // returned on stack
+};
+
+enum TRUST
+{
+    TRUSTdefault = 0,
+    TRUSTsystem = 1,    // @system (same as TRUSTdefault)
+    TRUSTtrusted = 2,   // @trusted
+    TRUSTsafe = 3,      // @safe
+};
+
+// in hdrgen.c
+void trustToBuffer(OutBuffer *buf, TRUST trust);
+const char *trustToChars(TRUST trust);
+
+enum TRUSTformat
+{
+    TRUSTformatDefault,  // do not emit @system when trust == TRUSTdefault
+    TRUSTformatSystem,   // emit @system when trust == TRUSTdefault
+};
+
+enum PURE
+{
+    PUREimpure = 0,     // not pure at all
+    PUREfwdref = 1,     // it's pure, but not known which level yet
+    PUREweak = 2,       // no mutable globals are read or written
+    PUREconst = 3,      // parameters are values or const
+    PUREstrong = 4,     // parameters are values or immutable
+};
+
+class TypeFunction : public TypeNext
+{
+public:
+    // .next is the return type
+
+    Parameters *parameters;     // function parameters
+    int varargs;        // 1: T t, ...) style for variable number of arguments
+                        // 2: T t ...) style for variable number of arguments
+    bool isnothrow;     // true: nothrow
+    bool isnogc;        // true: is @nogc
+    bool isproperty;    // can be called without parentheses
+    bool isref;         // true: returns a reference
+    bool isreturn;      // true: 'this' is returned by ref
+    bool isscope;       // true: 'this' is scope
+    bool isscopeinferred; // true: 'this' is scope from inference
+    LINK linkage;  // calling convention
+    TRUST trust;   // level of trust
+    PURE purity;   // PURExxxx
+    unsigned char iswild;   // bit0: inout on params, bit1: inout on qualifier
+    Expressions *fargs; // function arguments
+
+    int inuse;
+
+    TypeFunction(Parameters *parameters, Type *treturn, int varargs, LINK linkage, StorageClass stc = 0);
+    static TypeFunction *create(Parameters *parameters, Type *treturn, int varargs, LINK linkage, StorageClass stc = 0);
+    const char *kind();
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    void purityLevel();
+    bool hasLazyParameters();
+    bool parameterEscapes(Parameter *p);
+    StorageClass parameterStorageClass(Parameter *p);
+    Type *addStorageClass(StorageClass stc);
+
+    /** For each active attribute (ref/const/nogc/etc) call fp with a void* for the
+    work param and a string representation of the attribute. */
+    int attributesApply(void *param, int (*fp)(void *, const char *), TRUSTformat trustFormat = TRUSTformatDefault);
+
+    Type *substWildTo(unsigned mod);
+    MATCH callMatch(Type *tthis, Expressions *toargs, int flag = 0);
+    bool checkRetType(Loc loc);
+
+    Expression *defaultInit(Loc loc) /*const*/;
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeDelegate : public TypeNext
+{
+public:
+    // .next is a TypeFunction
+
+    TypeDelegate(Type *t);
+    static TypeDelegate *create(Type *t);
+    const char *kind();
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    Type *addStorageClass(StorageClass stc);
+    d_uns64 size(Loc loc) /*const*/;
+    unsigned alignsize() /*const*/;
+    MATCH implicitConvTo(Type *to);
+    Expression *defaultInit(Loc loc);
+    bool isZeroInit(Loc loc) /*const*/;
+    bool isBoolean() /*const*/;
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    bool hasPointers() /*const*/;
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeQualified : public Type
+{
+public:
+    Loc loc;
+    // array of Identifier and TypeInstance,
+    // representing ident.ident!tiargs.ident. ... etc.
+    Objects idents;
+
+    TypeQualified(TY ty, Loc loc);
+    void syntaxCopyHelper(TypeQualified *t);
+    void addIdent(Identifier *ident);
+    void addInst(TemplateInstance *inst);
+    void addIndex(RootObject *expr);
+    d_uns64 size(Loc loc);
+
+    void resolveTupleIndex(Loc loc, Scope *sc, Dsymbol *s,
+        Expression **pe, Type **pt, Dsymbol **ps, RootObject *oindex);
+    void resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym,
+        Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeIdentifier : public TypeQualified
+{
+public:
+    Identifier *ident;
+    Dsymbol *originalSymbol; // The symbol representing this identifier, before alias resolution
+
+    TypeIdentifier(Loc loc, Identifier *ident);
+    const char *kind();
+    Type *syntaxCopy();
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+    Dsymbol *toDsymbol(Scope *sc);
+    Type *semantic(Loc loc, Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Similar to TypeIdentifier, but with a TemplateInstance as the root
+ */
+class TypeInstance : public TypeQualified
+{
+public:
+    TemplateInstance *tempinst;
+
+    TypeInstance(Loc loc, TemplateInstance *tempinst);
+    const char *kind();
+    Type *syntaxCopy();
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+    Type *semantic(Loc loc, Scope *sc);
+    Dsymbol *toDsymbol(Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeTypeof : public TypeQualified
+{
+public:
+    Expression *exp;
+    int inuse;
+
+    TypeTypeof(Loc loc, Expression *exp);
+    const char *kind();
+    Type *syntaxCopy();
+    Dsymbol *toDsymbol(Scope *sc);
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+    Type *semantic(Loc loc, Scope *sc);
+    d_uns64 size(Loc loc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeReturn : public TypeQualified
+{
+public:
+    TypeReturn(Loc loc);
+    const char *kind();
+    Type *syntaxCopy();
+    Dsymbol *toDsymbol(Scope *sc);
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+    Type *semantic(Loc loc, Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// Whether alias this dependency is recursive or not.
+enum AliasThisRec
+{
+    RECno = 0,      // no alias this recursion
+    RECyes = 1,     // alias this has recursive dependency
+    RECfwdref = 2,  // not yet known
+    RECtypeMask = 3,// mask to read no/yes/fwdref
+
+    RECtracing = 0x4, // mark in progress of implicitConvTo/deduceWild
+    RECtracingDT = 0x8, // mark in progress of deduceType
+};
+
+class TypeStruct : public Type
+{
+public:
+    StructDeclaration *sym;
+    AliasThisRec att;
+    CPPMANGLE cppmangle;
+
+    TypeStruct(StructDeclaration *sym);
+    static TypeStruct *create(StructDeclaration *sym);
+    const char *kind();
+    d_uns64 size(Loc loc);
+    unsigned alignsize();
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    Dsymbol *toDsymbol(Scope *sc);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    structalign_t alignment();
+    Expression *defaultInit(Loc loc);
+    Expression *defaultInitLiteral(Loc loc);
+    bool isZeroInit(Loc loc) /*const*/;
+    bool isAssignable();
+    bool isBoolean() /*const*/;
+    bool needsDestruction() /*const*/;
+    bool needsNested();
+    bool hasPointers();
+    bool hasVoidInitPointers();
+    MATCH implicitConvTo(Type *to);
+    MATCH constConv(Type *to);
+    unsigned char deduceWild(Type *t, bool isRef);
+    Type *toHeadMutable();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeEnum : public Type
+{
+public:
+    EnumDeclaration *sym;
+
+    TypeEnum(EnumDeclaration *sym);
+    const char *kind();
+    Type *syntaxCopy();
+    d_uns64 size(Loc loc);
+    unsigned alignsize();
+    Type *semantic(Loc loc, Scope *sc);
+    Dsymbol *toDsymbol(Scope *sc);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    Expression *getProperty(Loc loc, Identifier *ident, int flag);
+    bool isintegral();
+    bool isfloating();
+    bool isreal();
+    bool isimaginary();
+    bool iscomplex();
+    bool isscalar();
+    bool isunsigned();
+    bool isBoolean();
+    bool isString();
+    bool isAssignable();
+    bool needsDestruction();
+    bool needsNested();
+    MATCH implicitConvTo(Type *to);
+    MATCH constConv(Type *to);
+    Type *toBasetype();
+    Expression *defaultInit(Loc loc);
+    bool isZeroInit(Loc loc);
+    bool hasPointers();
+    bool hasVoidInitPointers();
+    Type *nextOf();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeClass : public Type
+{
+public:
+    ClassDeclaration *sym;
+    AliasThisRec att;
+    CPPMANGLE cppmangle;
+
+    TypeClass(ClassDeclaration *sym);
+    const char *kind();
+    d_uns64 size(Loc loc) /*const*/;
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    Dsymbol *toDsymbol(Scope *sc);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+    ClassDeclaration *isClassHandle();
+    bool isBaseOf(Type *t, int *poffset);
+    MATCH implicitConvTo(Type *to);
+    MATCH constConv(Type *to);
+    unsigned char deduceWild(Type *t, bool isRef);
+    Type *toHeadMutable();
+    Expression *defaultInit(Loc loc);
+    bool isZeroInit(Loc loc) /*const*/;
+    bool isscope() /*const*/;
+    bool isBoolean() /*const*/;
+    bool hasPointers() /*const*/;
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeTuple : public Type
+{
+public:
+    Parameters *arguments;      // types making up the tuple
+
+    TypeTuple(Parameters *arguments);
+    TypeTuple(Expressions *exps);
+    static TypeTuple *create(Parameters *arguments);
+    TypeTuple();
+    TypeTuple(Type *t1);
+    TypeTuple(Type *t1, Type *t2);
+    const char *kind();
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    bool equals(RootObject *o);
+    Expression *getProperty(Loc loc, Identifier *ident, int flag);
+    Expression *defaultInit(Loc loc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeSlice : public TypeNext
+{
+public:
+    Expression *lwr;
+    Expression *upr;
+
+    TypeSlice(Type *next, Expression *lwr, Expression *upr);
+    const char *kind();
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeNull : public Type
+{
+public:
+    TypeNull();
+    const char *kind();
+
+    Type *syntaxCopy();
+    MATCH implicitConvTo(Type *to);
+    bool isBoolean() /*const*/;
+
+    d_uns64 size(Loc loc) /*const*/;
+    Expression *defaultInit(Loc loc) /*const*/;
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+//enum InOut { None, In, Out, InOut, Lazy };
+
+class Parameter : public RootObject
+{
+public:
+    //enum InOut inout;
+    StorageClass storageClass;
+    Type *type;
+    Identifier *ident;
+    Expression *defaultArg;
+
+    Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg);
+    static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg);
+    Parameter *syntaxCopy();
+    Type *isLazyArray();
+    // kludge for template.isType()
+    int dyncast() const { return DYNCAST_PARAMETER; }
+    virtual void accept(Visitor *v) { v->visit(this); }
+
+    static Parameters *arraySyntaxCopy(Parameters *parameters);
+    static size_t dim(Parameters *parameters);
+    static Parameter *getNth(Parameters *parameters, d_size_t nth, d_size_t *pn = NULL);
+    const char *toChars();
+    bool isCovariant(bool returnByRef, const Parameter *p) const;
+    static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to);
+};
+
+bool arrayTypeCompatible(Loc loc, Type *t1, Type *t2);
+bool arrayTypeCompatibleWithoutCasting(Loc loc, Type *t1, Type *t2);
+
+#endif /* DMD_MTYPE_H */
diff --git a/gcc/d/dfrontend/newdelete.c b/gcc/d/dfrontend/newdelete.c
new file mode 100644
index 00000000000..3c8c40ac7f5
--- /dev/null
+++ b/gcc/d/dfrontend/newdelete.c
@@ -0,0 +1,59 @@
+
+/* Copyright (c) 2000-2014 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/dlang/dmd/blob/master/src/root/rmem.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__has_feature)
+# if __has_feature(address_sanitizer)
+# define USE_ASAN_NEW_DELETE
+# endif
+#elif defined(__SANITIZE_ADDRESS__)
+# define USE_ASAN_NEW_DELETE
+#endif
+
+#if !defined(USE_ASAN_NEW_DELETE)
+
+#if 1
+
+extern "C"
+{
+    void *allocmemory(size_t m_size);
+}
+
+void * operator new(size_t m_size)
+{
+    return allocmemory(m_size);
+}
+
+void operator delete(void *p)
+{
+}
+
+#else
+
+void * operator new(size_t m_size)
+{
+    void *p = malloc(m_size);
+    if (p)
+        return p;
+    printf("Error: out of memory\n");
+    exit(EXIT_FAILURE);
+    return p;
+}
+
+void operator delete(void *p)
+{
+    free(p);
+}
+
+#endif
+
+#endif
diff --git a/gcc/d/dfrontend/nogc.c b/gcc/d/dfrontend/nogc.c
new file mode 100644
index 00000000000..380f928f684
--- /dev/null
+++ b/gcc/d/dfrontend/nogc.c
@@ -0,0 +1,242 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/nogc.c
+ */
+
+#include "mars.h"
+#include "init.h"
+#include "visitor.h"
+#include "expression.h"
+#include "statement.h"
+#include "declaration.h"
+#include "id.h"
+#include "module.h"
+#include "scope.h"
+#include "tokens.h"
+#include "aggregate.h"
+
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+
+void FuncDeclaration::printGCUsage(Loc loc, const char* warn)
+{
+    if (!global.params.vgc)
+        return;
+
+    Module *m = getModule();
+    if (m && m->isRoot() && !inUnittest())
+    {
+        fprintf(global.stdmsg, "%s: vgc: %s\n", loc.toChars(), warn);
+    }
+}
+
+/**************************************
+ * Look for GC-allocations
+ */
+class NOGCVisitor : public StoppableVisitor
+{
+public:
+    FuncDeclaration *f;
+    bool err;
+
+    NOGCVisitor(FuncDeclaration *f)
+    {
+        this->f = f;
+        this->err = false;
+    }
+
+    void doCond(Expression *exp)
+    {
+        if (exp)
+            walkPostorder(exp, this);
+    }
+
+    void visit(Expression *e)
+    {
+    }
+
+    void visit(DeclarationExp *e)
+    {
+        // Note that, walkPostorder does not support DeclarationExp today.
+        VarDeclaration *v = e->declaration->isVarDeclaration();
+        if (v && !(v->storage_class & STCmanifest) && !v->isDataseg() && v->_init)
+        {
+            if (ExpInitializer *ei = v->_init->isExpInitializer())
+            {
+                doCond(ei->exp);
+            }
+        }
+    }
+
+    void visit(CallExp *e)
+    {
+    }
+
+    void visit(ArrayLiteralExp *e)
+    {
+        if (e->type->ty != Tarray || !e->elements || !e->elements->dim)
+            return;
+
+        if (f->setGC())
+        {
+            e->error("array literal in @nogc %s '%s' may cause GC allocation",
+                f->kind(), f->toPrettyChars());
+            err = true;
+            return;
+        }
+        f->printGCUsage(e->loc, "array literal may cause GC allocation");
+    }
+
+    void visit(AssocArrayLiteralExp *e)
+    {
+        if (!e->keys->dim)
+            return;
+
+        if (f->setGC())
+        {
+            e->error("associative array literal in @nogc %s '%s' may cause GC allocation",
+                f->kind(), f->toPrettyChars());
+            err = true;
+            return;
+        }
+        f->printGCUsage(e->loc, "associative array literal may cause GC allocation");
+    }
+
+    void visit(NewExp *e)
+    {
+        if (e->member && !e->member->isNogc() && f->setGC())
+        {
+            // @nogc-ness is already checked in NewExp::semantic
+            return;
+        }
+        if (e->onstack)
+            return;
+        if (e->allocator)
+            return;
+
+        if (f->setGC())
+        {
+            e->error("cannot use 'new' in @nogc %s '%s'",
+                f->kind(), f->toPrettyChars());
+            err = true;
+            return;
+        }
+        f->printGCUsage(e->loc, "'new' causes GC allocation");
+    }
+
+    void visit(DeleteExp *e)
+    {
+        if (e->e1->op == TOKvar)
+        {
+            VarDeclaration *v =  ((VarExp *)e->e1)->var->isVarDeclaration();
+            if (v && v->onstack)
+                return;     // delete for scope allocated class object
+        }
+
+        Type *tb = e->e1->type->toBasetype();
+        AggregateDeclaration *ad = NULL;
+        switch (tb->ty)
+        {
+        case Tclass:
+            ad = ((TypeClass *)tb)->sym;
+            break;
+
+        case Tpointer:
+            tb = ((TypePointer *)tb)->next->toBasetype();
+            if (tb->ty == Tstruct)
+                ad = ((TypeStruct *)tb)->sym;
+            break;
+
+        default:
+            break;
+        }
+        if (ad && ad->aggDelete)
+            return;
+
+        if (f->setGC())
+        {
+            e->error("cannot use 'delete' in @nogc %s '%s'",
+                f->kind(), f->toPrettyChars());
+            err = true;
+            return;
+        }
+        f->printGCUsage(e->loc, "'delete' requires GC");
+    }
+
+    void visit(IndexExp* e)
+    {
+        Type *t1b = e->e1->type->toBasetype();
+        if (t1b->ty == Taarray)
+        {
+            if (f->setGC())
+            {
+                e->error("indexing an associative array in @nogc %s '%s' may cause GC allocation",
+                    f->kind(), f->toPrettyChars());
+                err = true;
+                return;
+            }
+            f->printGCUsage(e->loc, "indexing an associative array may cause GC allocation");
+        }
+    }
+
+    void visit(AssignExp *e)
+    {
+        if (e->e1->op == TOKarraylength)
+        {
+            if (f->setGC())
+            {
+                e->error("setting 'length' in @nogc %s '%s' may cause GC allocation",
+                    f->kind(), f->toPrettyChars());
+                err = true;
+                return;
+            }
+            f->printGCUsage(e->loc, "setting 'length' may cause GC allocation");
+        }
+    }
+
+    void visit(CatAssignExp *e)
+    {
+        if (f->setGC())
+        {
+            e->error("cannot use operator ~= in @nogc %s '%s'",
+                f->kind(), f->toPrettyChars());
+            err = true;
+            return;
+        }
+        f->printGCUsage(e->loc, "operator ~= may cause GC allocation");
+    }
+
+    void visit(CatExp *e)
+    {
+        if (f->setGC())
+        {
+            e->error("cannot use operator ~ in @nogc %s '%s'",
+                f->kind(), f->toPrettyChars());
+            err = true;
+            return;
+        }
+        f->printGCUsage(e->loc, "operator ~ may cause GC allocation");
+    }
+};
+
+Expression *checkGC(Scope *sc, Expression *e)
+{
+    FuncDeclaration *f = sc->func;
+    if (e && e->op != TOKerror &&
+        f && sc->intypeof != 1 && !(sc->flags & SCOPEctfe) &&
+        (f->type->ty == Tfunction && ((TypeFunction *)f->type)->isnogc ||
+         (f->flags & FUNCFLAGnogcInprocess) ||
+         global.params.vgc))
+    {
+        NOGCVisitor gcv(f);
+        walkPostorder(e, &gcv);
+        if (gcv.err)
+            return new ErrorExp();
+    }
+    return e;
+}
diff --git a/gcc/d/dfrontend/nspace.c b/gcc/d/dfrontend/nspace.c
new file mode 100644
index 00000000000..770eab4a6b3
--- /dev/null
+++ b/gcc/d/dfrontend/nspace.c
@@ -0,0 +1,229 @@
+
+// Compiler implementation of the D programming language
+// Copyright: Copyright (c) 2014 by Digital Mars, All Rights Reserved
+// Authors: Walter Bright, http://www.digitalmars.com
+// License: http://boost.org/LICENSE_1_0.txt
+// Source: https://github.com/D-Programming-Language/dmd/blob/master/src/nspace.c
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "nspace.h"
+#include "identifier.h"
+#include "scope.h"
+
+/* This implements namespaces.
+ */
+
+Nspace::Nspace(Loc loc, Identifier *ident, Dsymbols *members)
+    : ScopeDsymbol(ident)
+{
+    //printf("Nspace::Nspace(ident = %s)\n", ident->toChars());
+    this->loc = loc;
+    this->members = members;
+}
+
+Dsymbol *Nspace::syntaxCopy(Dsymbol *s)
+{
+    Nspace *ns = new Nspace(loc, ident, NULL);
+    return ScopeDsymbol::syntaxCopy(ns);
+}
+
+void Nspace::semantic(Scope *sc)
+{
+    if (semanticRun >= PASSsemantic)
+        return;
+    semanticRun = PASSsemantic;
+#if LOG
+    printf("+Nspace::semantic('%s')\n", toChars());
+#endif
+    if (_scope)
+    {
+        sc = _scope;
+        _scope = NULL;
+    }
+    parent = sc->parent;
+    if (members)
+    {
+        if (!symtab)
+            symtab = new DsymbolTable();
+
+        // The namespace becomes 'imported' into the enclosing scope
+        for (Scope *sce = sc; 1; sce = sce->enclosing)
+        {
+            ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym;
+            if (sds)
+            {
+                sds->importScope(this, Prot(PROTpublic));
+                break;
+            }
+        }
+
+        assert(sc);
+        sc = sc->push(this);
+        sc->linkage = LINKcpp;          // note that namespaces imply C++ linkage
+        sc->parent = this;
+
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            //printf("add %s to scope %s\n", s->toChars(), toChars());
+            s->addMember(sc, this);
+        }
+
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            s->setScope(sc);
+        }
+
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            s->importAll(sc);
+        }
+
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+#if LOG
+            printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind());
+#endif
+            s->semantic(sc);
+        }
+        sc->pop();
+    }
+#if LOG
+    printf("-Nspace::semantic('%s')\n", toChars());
+#endif
+}
+
+void Nspace::semantic2(Scope *sc)
+{
+    if (semanticRun >= PASSsemantic2)
+        return;
+    semanticRun = PASSsemantic2;
+#if LOG
+    printf("+Nspace::semantic2('%s')\n", toChars());
+#endif
+    if (members)
+    {
+        assert(sc);
+        sc = sc->push(this);
+        sc->linkage = LINKcpp;
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+#if LOG
+            printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind());
+#endif
+            s->semantic2(sc);
+        }
+        sc->pop();
+    }
+#if LOG
+    printf("-Nspace::semantic2('%s')\n", toChars());
+#endif
+}
+
+void Nspace::semantic3(Scope *sc)
+{
+    if (semanticRun >= PASSsemantic3)
+        return;
+    semanticRun = PASSsemantic3;
+#if LOG
+    printf("Nspace::semantic3('%s')\n", toChars());
+#endif
+    if (members)
+    {
+        sc = sc->push(this);
+        sc->linkage = LINKcpp;
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            s->semantic3(sc);
+        }
+        sc->pop();
+    }
+}
+
+const char *Nspace::kind()
+{
+    return "namespace";
+}
+
+bool Nspace::oneMember(Dsymbol **ps, Identifier *ident)
+{
+    return Dsymbol::oneMember(ps, ident);
+}
+
+Dsymbol *Nspace::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("%s::Nspace::search('%s')\n", toChars(), ident->toChars());
+    if (_scope && !symtab)
+        semantic(_scope);
+
+    if (!members || !symtab) // opaque or semantic() is not yet called
+    {
+        error("is forward referenced when looking for '%s'", ident->toChars());
+        return NULL;
+    }
+
+    return ScopeDsymbol::search(loc, ident, flags);
+}
+
+int Nspace::apply(Dsymbol_apply_ft_t fp, void *param)
+{
+    if (members)
+    {
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            if (s)
+            {
+                if (s->apply(fp, param))
+                    return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+bool Nspace::hasPointers()
+{
+    //printf("Nspace::hasPointers() %s\n", toChars());
+
+    if (members)
+    {
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            //printf(" s = %s %s\n", s->kind(), s->toChars());
+            if (s->hasPointers())
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void Nspace::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
+{
+    //printf("Nspace::setFieldOffset() %s\n", toChars());
+    if (_scope)                  // if fwd reference
+        semantic(NULL);         // try to resolve it
+    if (members)
+    {
+        for (size_t i = 0; i < members->dim; i++)
+        {
+            Dsymbol *s = (*members)[i];
+            //printf("\t%s\n", s->toChars());
+            s->setFieldOffset(ad, poffset, isunion);
+        }
+    }
+}
diff --git a/gcc/d/dfrontend/nspace.h b/gcc/d/dfrontend/nspace.h
new file mode 100644
index 00000000000..dcaa607a531
--- /dev/null
+++ b/gcc/d/dfrontend/nspace.h
@@ -0,0 +1,42 @@
+/**
+ * Compiler implementation of the
+ * $(LINK2 http://www.dlang.org, D programming language).
+ *
+ * Copyright:   Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved
+ * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ */
+
+#ifndef DMD_NSPACE_H
+#define DMD_NSPACE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+
+/* A namespace corresponding to a C++ namespace.
+ * Implies extern(C++).
+ */
+
+class Nspace : public ScopeDsymbol
+{
+  public:
+    Nspace(Loc loc, Identifier *ident, Dsymbols *members);
+
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    bool oneMember(Dsymbol **ps, Identifier *ident);
+    Dsymbol *search(Loc loc, Identifier *ident, int flags = SearchLocalsOnly);
+    int apply(Dsymbol_apply_ft_t fp, void *param);
+    bool hasPointers();
+    void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+    const char *kind();
+    Nspace *isNspace() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#endif /* DMD_NSPACE_H */
diff --git a/gcc/d/dfrontend/objc.c b/gcc/d/dfrontend/objc.c
new file mode 100644
index 00000000000..3e56eb11bf4
--- /dev/null
+++ b/gcc/d/dfrontend/objc.c
@@ -0,0 +1,85 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 2015 by Digital Mars
+ * All Rights Reserved
+ * written by Michel Fortin
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/objc_stubs.c
+ */
+
+#include "objc.h"
+#include "aggregate.h"
+#include "scope.h"
+
+class FuncDeclaration;
+
+// MARK: ObjcSelector
+
+ObjcSelector::ObjcSelector(const char *sv, size_t len, size_t pcount)
+{
+    printf("Should never be called when D_OBJC is false\n");
+    assert(0);
+}
+
+ObjcSelector *ObjcSelector::lookup(const char *s)
+{
+    printf("Should never be called when D_OBJC is false\n");
+    assert(0);
+    return NULL;
+}
+
+ObjcSelector *ObjcSelector::lookup(const char *s, size_t len, size_t pcount)
+{
+    printf("Should never be called when D_OBJC is false\n");
+    assert(0);
+    return NULL;
+}
+
+ObjcSelector *ObjcSelector::create(FuncDeclaration *fdecl)
+{
+    printf("Should never be called when D_OBJC is false\n");
+    assert(0);
+    return NULL;
+}
+
+class UnsupportedObjc : public Objc
+{
+    void setObjc(ClassDeclaration *cd)
+    {
+        cd->error("Objective-C classes not supported");
+    }
+
+    void setObjc(InterfaceDeclaration *id)
+    {
+        id->error("Objective-C interfaces not supported");
+    }
+
+    void setSelector(FuncDeclaration *, Scope *)
+    {
+        // noop
+    }
+
+    void validateSelector(FuncDeclaration *)
+    {
+        // noop
+    }
+
+    void checkLinkage(FuncDeclaration *)
+    {
+        // noop
+    }
+};
+
+static Objc *_objc;
+
+Objc *objc()
+{
+    return _objc;
+}
+
+void Objc::_init()
+{
+    _objc = new UnsupportedObjc();
+}
diff --git a/gcc/d/dfrontend/objc.h b/gcc/d/dfrontend/objc.h
new file mode 100644
index 00000000000..7dba2086c95
--- /dev/null
+++ b/gcc/d/dfrontend/objc.h
@@ -0,0 +1,57 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 2015 by Digital Mars
+ * All Rights Reserved
+ * written by Michel Fortin
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/objc.h
+ */
+
+#ifndef DMD_OBJC_H
+#define DMD_OBJC_H
+
+#include "root.h"
+#include "stringtable.h"
+
+class Identifier;
+class FuncDeclaration;
+class ClassDeclaration;
+class InterfaceDeclaration;
+struct Scope;
+class StructDeclaration;
+
+struct ObjcSelector
+{
+    static StringTable stringtable;
+    static StringTable vTableDispatchSelectors;
+    static int incnum;
+
+    const char *stringvalue;
+    size_t stringlen;
+    size_t paramCount;
+
+    static void _init();
+
+    ObjcSelector(const char *sv, size_t len, size_t pcount);
+
+    static ObjcSelector *lookup(const char *s);
+    static ObjcSelector *lookup(const char *s, size_t len, size_t pcount);
+
+    static ObjcSelector *create(FuncDeclaration *fdecl);
+};
+
+class Objc
+{
+public:
+    static void _init();
+
+    virtual void setObjc(ClassDeclaration* cd) = 0;
+    virtual void setObjc(InterfaceDeclaration*) = 0;
+    virtual void setSelector(FuncDeclaration*, Scope* sc) = 0;
+    virtual void validateSelector(FuncDeclaration* fd) = 0;
+    virtual void checkLinkage(FuncDeclaration* fd) = 0;
+};
+
+#endif /* DMD_OBJC_H */
diff --git a/gcc/d/dfrontend/object.h b/gcc/d/dfrontend/object.h
new file mode 100644
index 00000000000..629ec812ab0
--- /dev/null
+++ b/gcc/d/dfrontend/object.h
@@ -0,0 +1,68 @@
+
+/* Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/dlang/dmd/blob/master/src/root/object.h
+ */
+
+#ifndef OBJECT_H
+#define OBJECT_H
+
+#define POSIX (__linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun)
+
+#if __DMC__
+#pragma once
+#endif
+
+#include <stddef.h>
+
+typedef size_t hash_t;
+
+struct OutBuffer;
+
+enum DYNCAST
+{
+    DYNCAST_OBJECT,
+    DYNCAST_EXPRESSION,
+    DYNCAST_DSYMBOL,
+    DYNCAST_TYPE,
+    DYNCAST_IDENTIFIER,
+    DYNCAST_TUPLE,
+    DYNCAST_PARAMETER,
+    DYNCAST_STATEMENT,
+};
+
+/*
+ * Root of our class library.
+ */
+class RootObject
+{
+public:
+    RootObject() { }
+
+    virtual bool equals(RootObject *o);
+
+    /**
+     * Return <0, ==0, or >0 if this is less than, equal to, or greater than obj.
+     * Useful for sorting Objects.
+     */
+    virtual int compare(RootObject *obj);
+
+    /**
+     * Pretty-print an Object. Useful for debugging the old-fashioned way.
+     */
+    virtual void print();
+
+    virtual const char *toChars();
+    virtual void toBuffer(OutBuffer *buf);
+
+    /**
+     * Used as a replacement for dynamic_cast. Returns a unique number
+     * defined by the library user. For Object, the return value is 0.
+     */
+    virtual int dyncast() const;
+};
+
+#endif
diff --git a/gcc/d/dfrontend/opover.c b/gcc/d/dfrontend/opover.c
new file mode 100644
index 00000000000..d6bc3af0bbd
--- /dev/null
+++ b/gcc/d/dfrontend/opover.c
@@ -0,0 +1,1964 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/opover.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>                     // memset()
+
+#include "rmem.h"
+
+#include "mtype.h"
+#include "init.h"
+#include "expression.h"
+#include "statement.h"
+#include "scope.h"
+#include "id.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "template.h"
+#include "tokens.h"
+
+static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *parameters);
+static int inferApplyArgTypesY(TypeFunction *tf, Parameters *parameters, int flags = 0);
+Expression *compare_overload(BinExp *e, Scope *sc, Identifier *id);
+bool MODimplicitConv(MOD modfrom, MOD modto);
+Expression *trySemantic(Expression *e, Scope *sc);
+Expression *binSemanticProp(BinExp *e, Scope *sc);
+Expression *semantic(Expression *e, Scope *sc);
+
+/******************************** Expression **************************/
+
+
+/***********************************
+ * Determine if operands of binary op can be reversed
+ * to fit operator overload.
+ */
+
+bool isCommutative(TOK op)
+{
+    switch (op)
+    {
+        case TOKadd:
+        case TOKmul:
+        case TOKand:
+        case TOKor:
+        case TOKxor:
+
+        // EqualExp
+        case TOKequal:
+        case TOKnotequal:
+
+        // CmpExp
+        case TOKlt:
+        case TOKle:
+        case TOKgt:
+        case TOKge:
+            return true;
+
+        default:
+            break;
+    }
+    return false;
+}
+
+/***********************************
+ * Get Identifier for operator overload.
+ */
+
+static Identifier *opId(Expression *e)
+{
+    class OpIdVisitor : public Visitor
+    {
+    public:
+        Identifier *id;
+        void visit(Expression *e)    { assert(0); }
+        void visit(UAddExp *e)       { id = Id::uadd; }
+        void visit(NegExp *e)        { id = Id::neg; }
+        void visit(ComExp *e)        { id = Id::com; }
+        void visit(CastExp *e)       { id = Id::_cast; }
+        void visit(InExp *e)         { id = Id::opIn; }
+        void visit(PostExp *e)       { id = (e->op == TOKplusplus) ? Id::postinc : Id::postdec; }
+        void visit(AddExp *e)        { id = Id::add; }
+        void visit(MinExp *e)        { id = Id::sub; }
+        void visit(MulExp *e)        { id = Id::mul; }
+        void visit(DivExp *e)        { id = Id::div; }
+        void visit(ModExp *e)        { id = Id::mod; }
+        void visit(PowExp *e)        { id = Id::pow; }
+        void visit(ShlExp *e)        { id = Id::shl; }
+        void visit(ShrExp *e)        { id = Id::shr; }
+        void visit(UshrExp *e)       { id = Id::ushr; }
+        void visit(AndExp *e)        { id = Id::iand; }
+        void visit(OrExp *e)         { id = Id::ior; }
+        void visit(XorExp *e)        { id = Id::ixor; }
+        void visit(CatExp *e)        { id = Id::cat; }
+        void visit(AssignExp *e)     { id = Id::assign; }
+        void visit(AddAssignExp *e)  { id = Id::addass; }
+        void visit(MinAssignExp *e)  { id = Id::subass; }
+        void visit(MulAssignExp *e)  { id = Id::mulass; }
+        void visit(DivAssignExp *e)  { id = Id::divass; }
+        void visit(ModAssignExp *e)  { id = Id::modass; }
+        void visit(AndAssignExp *e)  { id = Id::andass; }
+        void visit(OrAssignExp *e)   { id = Id::orass; }
+        void visit(XorAssignExp *e)  { id = Id::xorass; }
+        void visit(ShlAssignExp *e)  { id = Id::shlass; }
+        void visit(ShrAssignExp *e)  { id = Id::shrass; }
+        void visit(UshrAssignExp *e) { id = Id::ushrass; }
+        void visit(CatAssignExp *e)  { id = Id::catass; }
+        void visit(PowAssignExp *e)  { id = Id::powass; }
+        void visit(EqualExp *e)      { id = Id::eq; }
+        void visit(CmpExp *e)        { id = Id::cmp; }
+        void visit(ArrayExp *e)      { id = Id::index; }
+        void visit(PtrExp *e)        { id = Id::opStar; }
+    };
+    OpIdVisitor v;
+    e->accept(&v);
+    return v.id;
+}
+
+/***********************************
+ * Get Identifier for reverse operator overload,
+ * NULL if not supported for this operator.
+ */
+
+static Identifier *opId_r(Expression *e)
+{
+    class OpIdRVisitor : public Visitor
+    {
+    public:
+        Identifier *id;
+        void visit(Expression *e) { id = NULL; }
+        void visit(InExp *e)      { id = Id::opIn_r; }
+        void visit(AddExp *e)     { id = Id::add_r; }
+        void visit(MinExp *e)     { id = Id::sub_r; }
+        void visit(MulExp *e)     { id = Id::mul_r; }
+        void visit(DivExp *e)     { id = Id::div_r; }
+        void visit(ModExp *e)     { id = Id::mod_r; }
+        void visit(PowExp *e)     { id = Id::pow_r; }
+        void visit(ShlExp *e)     { id = Id::shl_r; }
+        void visit(ShrExp *e)     { id = Id::shr_r; }
+        void visit(UshrExp *e)    { id = Id::ushr_r; }
+        void visit(AndExp *e)     { id = Id::iand_r; }
+        void visit(OrExp *e)      { id = Id::ior_r; }
+        void visit(XorExp *e)     { id = Id::ixor_r; }
+        void visit(CatExp *e)     { id = Id::cat_r; }
+    };
+    OpIdRVisitor v;
+    e->accept(&v);
+    return v.id;
+}
+
+/************************************
+ * If type is a class or struct, return the symbol for it,
+ * else NULL
+ */
+AggregateDeclaration *isAggregate(Type *t)
+{
+    t = t->toBasetype();
+    if (t->ty == Tclass)
+    {
+        return ((TypeClass *)t)->sym;
+    }
+    else if (t->ty == Tstruct)
+    {
+        return ((TypeStruct *)t)->sym;
+    }
+    return NULL;
+}
+
+/*******************************************
+ * Helper function to turn operator into template argument list
+ */
+Objects *opToArg(Scope *sc, TOK op)
+{
+    /* Remove the = from op=
+     */
+    switch (op)
+    {
+        case TOKaddass: op = TOKadd; break;
+        case TOKminass: op = TOKmin; break;
+        case TOKmulass: op = TOKmul; break;
+        case TOKdivass: op = TOKdiv; break;
+        case TOKmodass: op = TOKmod; break;
+        case TOKandass: op = TOKand; break;
+        case TOKorass:  op = TOKor;  break;
+        case TOKxorass: op = TOKxor; break;
+        case TOKshlass: op = TOKshl; break;
+        case TOKshrass: op = TOKshr; break;
+        case TOKushrass: op = TOKushr; break;
+        case TOKcatass: op = TOKcat; break;
+        case TOKpowass: op = TOKpow; break;
+    }
+    Expression *e = new StringExp(Loc(), (char *)Token::toChars(op));
+    e = semantic(e, sc);
+    Objects *tiargs = new Objects();
+    tiargs->push(e);
+    return tiargs;
+}
+
+/************************************
+ * Operator overload.
+ * Check for operator overload, if so, replace
+ * with function call.
+ * Return NULL if not an operator overload.
+ */
+
+Expression *op_overload(Expression *e, Scope *sc)
+{
+    class OpOverload : public Visitor
+    {
+    public:
+        Scope *sc;
+        Expression *result;
+
+        OpOverload(Scope *sc)
+            : sc(sc)
+        {
+            result = NULL;
+        }
+
+        void visit(Expression *e)
+        {
+            assert(0);
+        }
+
+        void visit(UnaExp *e)
+        {
+            //printf("UnaExp::op_overload() (%s)\n", e->toChars());
+
+            if (e->e1->op == TOKarray)
+            {
+                ArrayExp *ae = (ArrayExp *)e->e1;
+                ae->e1 = semantic(ae->e1, sc);
+                ae->e1 = resolveProperties(sc, ae->e1);
+                Expression *ae1old = ae->e1;
+
+                const bool maybeSlice =
+                    (ae->arguments->dim == 0 ||
+                     ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval);
+                IntervalExp *ie = NULL;
+                if (maybeSlice && ae->arguments->dim)
+                {
+                    assert((*ae->arguments)[0]->op == TOKinterval);
+                    ie = (IntervalExp *)(*ae->arguments)[0];
+                }
+
+                while (true)
+                {
+                    if (ae->e1->op == TOKerror)
+                    {
+                        result = ae->e1;
+                        return;
+                    }
+                    Expression *e0 = NULL;
+                    Expression *ae1save = ae->e1;
+                    ae->lengthVar = NULL;
+
+                    Type *t1b = ae->e1->type->toBasetype();
+                    AggregateDeclaration *ad = isAggregate(t1b);
+                    if (!ad)
+                        break;
+                    if (search_function(ad, Id::opIndexUnary))
+                    {
+                        // Deal with $
+                        result = resolveOpDollar(sc, ae, &e0);
+                        if (!result)    // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j)
+                            goto Lfallback;
+                        if (result->op == TOKerror)
+                            return;
+
+                        /* Rewrite op(a[arguments]) as:
+                         *      a.opIndexUnary!(op)(arguments)
+                         */
+                        Expressions *a = (Expressions *)ae->arguments->copy();
+                        Objects *tiargs = opToArg(sc, e->op);
+                        result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opIndexUnary, tiargs);
+                        result = new CallExp(e->loc, result, a);
+                        if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)()
+                            result = trySemantic(result, sc);
+                        else
+                            result = semantic(result, sc);
+                        if (result)
+                        {
+                            result = Expression::combine(e0, result);
+                            return;
+                        }
+                    }
+                Lfallback:
+                    if (maybeSlice && search_function(ad, Id::opSliceUnary))
+                    {
+                        // Deal with $
+                        result = resolveOpDollar(sc, ae, ie, &e0);
+                        if (result->op == TOKerror)
+                            return;
+
+                        /* Rewrite op(a[i..j]) as:
+                         *      a.opSliceUnary!(op)(i, j)
+                         */
+                        Expressions *a = new Expressions();
+                        if (ie)
+                        {
+                            a->push(ie->lwr);
+                            a->push(ie->upr);
+                        }
+                        Objects *tiargs = opToArg(sc, e->op);
+                        result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opSliceUnary, tiargs);
+                        result = new CallExp(e->loc, result, a);
+                        result = semantic(result, sc);
+                        result = Expression::combine(e0, result);
+                        return;
+                    }
+
+                    // Didn't find it. Forward to aliasthis
+                    if (ad->aliasthis && t1b != ae->att1)
+                    {
+                        if (!ae->att1 && t1b->checkAliasThisRec())
+                            ae->att1 = t1b;
+
+                        /* Rewrite op(a[arguments]) as:
+                         *      op(a.aliasthis[arguments])
+                         */
+                        ae->e1 = resolveAliasThis(sc, ae1save, true);
+                        if (ae->e1)
+                            continue;
+                    }
+                    break;
+                }
+                ae->e1 = ae1old;    // recovery
+                ae->lengthVar = NULL;
+            }
+
+            e->e1 = semantic(e->e1, sc);
+            e->e1 = resolveProperties(sc, e->e1);
+            if (e->e1->op == TOKerror)
+            {
+                result = e->e1;
+                return;
+            }
+
+            AggregateDeclaration *ad = isAggregate(e->e1->type);
+            if (ad)
+            {
+                Dsymbol *fd = NULL;
+        #if 1 // Old way, kept for compatibility with D1
+                if (e->op != TOKpreplusplus && e->op != TOKpreminusminus)
+                {
+                    fd = search_function(ad, opId(e));
+                    if (fd)
+                    {
+                        // Rewrite +e1 as e1.add()
+                        result = build_overload(e->loc, sc, e->e1, NULL, fd);
+                        return;
+                    }
+                }
+        #endif
+
+                /* Rewrite as:
+                 *      e1.opUnary!(op)()
+                 */
+                fd = search_function(ad, Id::opUnary);
+                if (fd)
+                {
+                    Objects *tiargs = opToArg(sc, e->op);
+                    result = new DotTemplateInstanceExp(e->loc, e->e1, fd->ident, tiargs);
+                    result = new CallExp(e->loc, result);
+                    result = semantic(result, sc);
+                    return;
+                }
+
+                // Didn't find it. Forward to aliasthis
+                if (ad->aliasthis && e->e1->type != e->att1)
+                {
+                    /* Rewrite op(e1) as:
+                     *      op(e1.aliasthis)
+                     */
+                    //printf("att una %s e1 = %s\n", Token::toChars(op), this->e1->type->toChars());
+                    Expression *e1 = new DotIdExp(e->loc, e->e1, ad->aliasthis->ident);
+                    UnaExp *ue = (UnaExp *)e->copy();
+                    if (!ue->att1 && e->e1->type->checkAliasThisRec())
+                        ue->att1 = e->e1->type;
+                    ue->e1 = e1;
+                    result = trySemantic(ue, sc);
+                    return;
+                }
+            }
+        }
+
+        void visit(ArrayExp *ae)
+        {
+            //printf("ArrayExp::op_overload() (%s)\n", ae->toChars());
+            ae->e1 = semantic(ae->e1, sc);
+            ae->e1 = resolveProperties(sc, ae->e1);
+            Expression *ae1old = ae->e1;
+
+            const bool maybeSlice =
+                (ae->arguments->dim == 0 ||
+                 ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval);
+            IntervalExp *ie = NULL;
+            if (maybeSlice && ae->arguments->dim)
+            {
+                assert((*ae->arguments)[0]->op == TOKinterval);
+                ie = (IntervalExp *)(*ae->arguments)[0];
+            }
+
+            while (true)
+            {
+                if (ae->e1->op == TOKerror)
+                {
+                    result = ae->e1;
+                    return;
+                }
+                Expression *e0 = NULL;
+                Expression *ae1save = ae->e1;
+                ae->lengthVar = NULL;
+
+                Type *t1b = ae->e1->type->toBasetype();
+                AggregateDeclaration *ad = isAggregate(t1b);
+                if (!ad)
+                {
+                    // If the non-aggregate expression ae->e1 is indexable or sliceable,
+                    // convert it to the corresponding concrete expression.
+                    if (t1b->ty == Tpointer ||
+                        t1b->ty == Tsarray ||
+                        t1b->ty == Tarray ||
+                        t1b->ty == Taarray ||
+                        t1b->ty == Ttuple ||
+                        t1b->ty == Tvector ||
+                        ae->e1->op == TOKtype)
+                    {
+                        // Convert to SliceExp
+                        if (maybeSlice)
+                        {
+                            result = new SliceExp(ae->loc, ae->e1, ie);
+                            result = semantic(result, sc);
+                            return;
+                        }
+                        // Convert to IndexExp
+                        if (ae->arguments->dim == 1)
+                        {
+                            result = new IndexExp(ae->loc, ae->e1, (*ae->arguments)[0]);
+                            result = semantic(result, sc);
+                            return;
+                        }
+                    }
+                    break;
+                }
+                if (search_function(ad, Id::index))
+                {
+                    // Deal with $
+                    result = resolveOpDollar(sc, ae, &e0);
+                    if (!result)    // a[i..j] might be: a.opSlice(i, j)
+                        goto Lfallback;
+                    if (result->op == TOKerror)
+                        return;
+
+                    /* Rewrite e1[arguments] as:
+                     *      e1.opIndex(arguments)
+                     */
+                    Expressions *a = (Expressions *)ae->arguments->copy();
+                    result = new DotIdExp(ae->loc, ae->e1, Id::index);
+                    result = new CallExp(ae->loc, result, a);
+                    if (maybeSlice) // a[] might be: a.opSlice()
+                        result = trySemantic(result, sc);
+                    else
+                        result = semantic(result, sc);
+                    if (result)
+                    {
+                        result = Expression::combine(e0, result);
+                        return;
+                    }
+                }
+            Lfallback:
+                if (maybeSlice && ae->e1->op == TOKtype)
+                {
+                    result = new SliceExp(ae->loc, ae->e1, ie);
+                    result = semantic(result, sc);
+                    result = Expression::combine(e0, result);
+                    return;
+                }
+                if (maybeSlice && search_function(ad, Id::slice))
+                {
+                    // Deal with $
+                    result = resolveOpDollar(sc, ae, ie, &e0);
+                    if (result->op == TOKerror)
+                        return;
+
+                    /* Rewrite a[i..j] as:
+                     *      a.opSlice(i, j)
+                     */
+                    Expressions *a = new Expressions();
+                    if (ie)
+                    {
+                        a->push(ie->lwr);
+                        a->push(ie->upr);
+                    }
+                    result = new DotIdExp(ae->loc, ae->e1, Id::slice);
+                    result = new CallExp(ae->loc, result, a);
+                    result = semantic(result, sc);
+                    result = Expression::combine(e0, result);
+                    return;
+                }
+
+                // Didn't find it. Forward to aliasthis
+                if (ad->aliasthis && t1b != ae->att1)
+                {
+                    if (!ae->att1 && t1b->checkAliasThisRec())
+                        ae->att1 = t1b;
+                    //printf("att arr e1 = %s\n", this->e1->type->toChars());
+
+                    /* Rewrite op(a[arguments]) as:
+                     *      op(a.aliasthis[arguments])
+                     */
+                    ae->e1 = resolveAliasThis(sc, ae1save, true);
+                    if (ae->e1)
+                        continue;
+                }
+                break;
+            }
+            ae->e1 = ae1old;    // recovery
+            ae->lengthVar = NULL;
+        }
+
+        /***********************************************
+         * This is mostly the same as UnaryExp::op_overload(), but has
+         * a different rewrite.
+         */
+        void visit(CastExp *e)
+        {
+            //printf("CastExp::op_overload() (%s)\n", e->toChars());
+            AggregateDeclaration *ad = isAggregate(e->e1->type);
+            if (ad)
+            {
+                Dsymbol *fd = NULL;
+                /* Rewrite as:
+                 *      e1.opCast!(T)()
+                 */
+                fd = search_function(ad, Id::_cast);
+                if (fd)
+                {
+        #if 1 // Backwards compatibility with D1 if opCast is a function, not a template
+                    if (fd->isFuncDeclaration())
+                    {
+                        // Rewrite as:  e1.opCast()
+                        result = build_overload(e->loc, sc, e->e1, NULL, fd);
+                        return;
+                    }
+        #endif
+                    Objects *tiargs = new Objects();
+                    tiargs->push(e->to);
+                    result = new DotTemplateInstanceExp(e->loc, e->e1, fd->ident, tiargs);
+                    result = new CallExp(e->loc, result);
+                    result = semantic(result, sc);
+                    return;
+                }
+
+                // Didn't find it. Forward to aliasthis
+                if (ad->aliasthis)
+                {
+                    /* Rewrite op(e1) as:
+                     *      op(e1.aliasthis)
+                     */
+                    Expression *e1 = new DotIdExp(e->loc, e->e1, ad->aliasthis->ident);
+                    result = e->copy();
+                    ((UnaExp *)result)->e1 = e1;
+                    result = trySemantic(result, sc);
+                    return;
+                }
+            }
+        }
+
+        void visit(BinExp *e)
+        {
+            //printf("BinExp::op_overload() (%s)\n", e->toChars());
+
+            Identifier *id = opId(e);
+            Identifier *id_r = opId_r(e);
+
+            Expressions args1;
+            Expressions args2;
+            int argsset = 0;
+
+            AggregateDeclaration *ad1 = isAggregate(e->e1->type);
+            AggregateDeclaration *ad2 = isAggregate(e->e2->type);
+
+            if (e->op == TOKassign && ad1 == ad2)
+            {
+                StructDeclaration *sd = ad1->isStructDeclaration();
+                if (sd && !sd->hasIdentityAssign)
+                {
+                    /* This is bitwise struct assignment. */
+                    return;
+                }
+            }
+
+            Dsymbol *s = NULL;
+            Dsymbol *s_r = NULL;
+
+        #if 1 // the old D1 scheme
+            if (ad1 && id)
+            {
+                s = search_function(ad1, id);
+            }
+            if (ad2 && id_r)
+            {
+                s_r = search_function(ad2, id_r);
+
+                // Bugzilla 12778: If both x.opBinary(y) and y.opBinaryRight(x) found,
+                // and they are exactly same symbol, x.opBinary(y) should be preferred.
+                if (s_r && s_r == s)
+                    s_r = NULL;
+            }
+        #endif
+
+            Objects *tiargs = NULL;
+            if (e->op == TOKplusplus || e->op == TOKminusminus)
+            {
+                // Bug4099 fix
+                if (ad1 && search_function(ad1, Id::opUnary))
+                    return;
+            }
+            if (!s && !s_r && e->op != TOKequal && e->op != TOKnotequal && e->op != TOKassign &&
+                e->op != TOKplusplus && e->op != TOKminusminus)
+            {
+                /* Try the new D2 scheme, opBinary and opBinaryRight
+                 */
+                if (ad1)
+                {
+                    s = search_function(ad1, Id::opBinary);
+                    if (s && !s->isTemplateDeclaration())
+                    {
+                        e->e1->error("%s.opBinary isn't a template", e->e1->toChars());
+                        result = new ErrorExp();
+                        return;
+                    }
+                }
+                if (ad2)
+                {
+                    s_r = search_function(ad2, Id::opBinaryRight);
+                    if (s_r && !s_r->isTemplateDeclaration())
+                    {
+                        e->e2->error("%s.opBinaryRight isn't a template", e->e2->toChars());
+                        result = new ErrorExp();
+                        return;
+                    }
+                    if (s_r && s_r == s)    // Bugzilla 12778
+                        s_r = NULL;
+                }
+
+                // Set tiargs, the template argument list, which will be the operator string
+                if (s || s_r)
+                {
+                    id = Id::opBinary;
+                    id_r = Id::opBinaryRight;
+                    tiargs = opToArg(sc, e->op);
+                }
+            }
+
+            if (s || s_r)
+            {
+                /* Try:
+                 *      a.opfunc(b)
+                 *      b.opfunc_r(a)
+                 * and see which is better.
+                 */
+
+                args1.setDim(1);
+                args1[0] = e->e1;
+                expandTuples(&args1);
+                args2.setDim(1);
+                args2[0] = e->e2;
+                expandTuples(&args2);
+                argsset = 1;
+
+                Match m;
+                memset(&m, 0, sizeof(m));
+                m.last = MATCHnomatch;
+
+                if (s)
+                {
+                    functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2);
+                    if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+                    {
+                        result = new ErrorExp();
+                        return;
+                    }
+                }
+
+                FuncDeclaration *lastf = m.lastf;
+
+                if (s_r)
+                {
+                    functionResolve(&m, s_r, e->loc, sc, tiargs, e->e2->type, &args1);
+                    if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+                    {
+                        result = new ErrorExp();
+                        return;
+                    }
+                }
+
+                if (m.count > 1)
+                {
+                    // Error, ambiguous
+                    e->error("overloads %s and %s both match argument list for %s",
+                            m.lastf->type->toChars(),
+                            m.nextf->type->toChars(),
+                            m.lastf->toChars());
+                }
+                else if (m.last <= MATCHnomatch)
+                {
+                    m.lastf = m.anyf;
+                    if (tiargs)
+                        goto L1;
+                }
+
+                if (e->op == TOKplusplus || e->op == TOKminusminus)
+                {
+                    // Kludge because operator overloading regards e++ and e--
+                    // as unary, but it's implemented as a binary.
+                    // Rewrite (e1 ++ e2) as e1.postinc()
+                    // Rewrite (e1 -- e2) as e1.postdec()
+                    result = build_overload(e->loc, sc, e->e1, NULL, m.lastf ? m.lastf : s);
+                }
+                else if (lastf && m.lastf == lastf || !s_r && m.last <= MATCHnomatch)
+                {
+                    // Rewrite (e1 op e2) as e1.opfunc(e2)
+                    result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s);
+                }
+                else
+                {
+                    // Rewrite (e1 op e2) as e2.opfunc_r(e1)
+                    result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s_r);
+                }
+                return;
+            }
+
+        L1:
+        #if 1 // Retained for D1 compatibility
+            if (isCommutative(e->op) && !tiargs)
+            {
+                s = NULL;
+                s_r = NULL;
+                if (ad1 && id_r)
+                {
+                    s_r = search_function(ad1, id_r);
+                }
+                if (ad2 && id)
+                {
+                    s = search_function(ad2, id);
+                    if (s && s == s_r)  // Bugzilla 12778
+                        s = NULL;
+                }
+
+                if (s || s_r)
+                {
+                    /* Try:
+                     *  a.opfunc_r(b)
+                     *  b.opfunc(a)
+                     * and see which is better.
+                     */
+
+                    if (!argsset)
+                    {
+                        args1.setDim(1);
+                        args1[0] = e->e1;
+                        expandTuples(&args1);
+                        args2.setDim(1);
+                        args2[0] = e->e2;
+                        expandTuples(&args2);
+                    }
+
+                    Match m;
+                    memset(&m, 0, sizeof(m));
+                    m.last = MATCHnomatch;
+
+                    if (s_r)
+                    {
+                        functionResolve(&m, s_r, e->loc, sc, tiargs, e->e1->type, &args2);
+                        if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+                        {
+                            result = new ErrorExp();
+                            return;
+                        }
+                    }
+
+                    FuncDeclaration *lastf = m.lastf;
+
+                    if (s)
+                    {
+                        functionResolve(&m, s, e->loc, sc, tiargs, e->e2->type, &args1);
+                        if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+                        {
+                            result = new ErrorExp();
+                            return;
+                        }
+                    }
+
+                    if (m.count > 1)
+                    {
+                        // Error, ambiguous
+                        e->error("overloads %s and %s both match argument list for %s",
+                                m.lastf->type->toChars(),
+                                m.nextf->type->toChars(),
+                                m.lastf->toChars());
+                    }
+                    else if (m.last <= MATCHnomatch)
+                    {
+                        m.lastf = m.anyf;
+                    }
+
+                    if (lastf && m.lastf == lastf || !s && m.last <= MATCHnomatch)
+                    {
+                        // Rewrite (e1 op e2) as e1.opfunc_r(e2)
+                        result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s_r);
+                    }
+                    else
+                    {
+                        // Rewrite (e1 op e2) as e2.opfunc(e1)
+                        result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s);
+                    }
+
+                    // When reversing operands of comparison operators,
+                    // need to reverse the sense of the op
+                    switch (e->op)
+                    {
+                        case TOKlt:     e->op = TOKgt;     break;
+                        case TOKgt:     e->op = TOKlt;     break;
+                        case TOKle:     e->op = TOKge;     break;
+                        case TOKge:     e->op = TOKle;     break;
+                    }
+
+                    return;
+                }
+            }
+        #endif
+
+            // Try alias this on first operand
+            if (ad1 && ad1->aliasthis &&
+                !(e->op == TOKassign && ad2 && ad1 == ad2))   // See Bugzilla 2943
+            {
+                /* Rewrite (e1 op e2) as:
+                 *      (e1.aliasthis op e2)
+                 */
+                if (e->att1 && e->e1->type == e->att1)
+                    return;
+                //printf("att bin e1 = %s\n", this->e1->type->toChars());
+                Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident);
+                BinExp *be = (BinExp *)e->copy();
+                if (!be->att1 && e->e1->type->checkAliasThisRec())
+                    be->att1 = e->e1->type;
+                be->e1 = e1;
+                result = trySemantic(be, sc);
+                return;
+            }
+
+            // Try alias this on second operand
+            /* Bugzilla 2943: make sure that when we're copying the struct, we don't
+             * just copy the alias this member
+             */
+            if (ad2 && ad2->aliasthis &&
+                !(e->op == TOKassign && ad1 && ad1 == ad2))
+            {
+                /* Rewrite (e1 op e2) as:
+                 *      (e1 op e2.aliasthis)
+                 */
+                if (e->att2 && e->e2->type == e->att2)
+                    return;
+                //printf("att bin e2 = %s\n", e->e2->type->toChars());
+                Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident);
+                BinExp *be = (BinExp *)e->copy();
+                if (!be->att2 && e->e2->type->checkAliasThisRec())
+                    be->att2 = e->e2->type;
+                be->e2 = e2;
+                result = trySemantic(be, sc);
+                return;
+            }
+            return;
+        }
+
+        static bool needsDirectEq(Type *t1, Type *t2, Scope *sc)
+        {
+            Type *t1n = t1->nextOf()->toBasetype();
+            Type *t2n = t2->nextOf()->toBasetype();
+            if (((t1n->ty == Tchar || t1n->ty == Twchar || t1n->ty == Tdchar) &&
+                 (t2n->ty == Tchar || t2n->ty == Twchar || t2n->ty == Tdchar)) ||
+                (t1n->ty == Tvoid || t2n->ty == Tvoid))
+            {
+                return false;
+            }
+            if (t1n->constOf() != t2n->constOf())
+                return true;
+
+            Type *t = t1n;
+            while (t->toBasetype()->nextOf())
+                t = t->nextOf()->toBasetype();
+            if (t->ty != Tstruct)
+                return false;
+
+            semanticTypeInfo(sc, t);
+            return ((TypeStruct *)t)->sym->hasIdentityEquals;
+        }
+
+        void visit(EqualExp *e)
+        {
+            //printf("EqualExp::op_overload() (%s)\n", e->toChars());
+
+            Type *t1 = e->e1->type->toBasetype();
+            Type *t2 = e->e2->type->toBasetype();
+
+            /* Check for array equality.
+             */
+            if ((t1->ty == Tarray || t1->ty == Tsarray) &&
+                (t2->ty == Tarray || t2->ty == Tsarray))
+            {
+                if (needsDirectEq(t1, t2, sc))
+                {
+                    /* Rewrite as:
+                     *      _ArrayEq(e1, e2)
+                     */
+                    Expression *eeq = new IdentifierExp(e->loc, Id::_ArrayEq);
+                    result = new CallExp(e->loc, eeq, e->e1, e->e2);
+                    if (e->op == TOKnotequal)
+                        result = new NotExp(e->loc, result);
+                    result = trySemantic(result, sc); // for better error message
+                    if (!result)
+                    {
+                        e->error("cannot compare %s and %s", t1->toChars(), t2->toChars());
+                        result = new ErrorExp();
+                    }
+                    return;
+                }
+            }
+
+            /* Check for class equality with null literal or typeof(null).
+             */
+            if (t1->ty == Tclass && e->e2->op == TOKnull ||
+                t2->ty == Tclass && e->e1->op == TOKnull)
+            {
+                e->error("use '%s' instead of '%s' when comparing with null",
+                    Token::toChars(e->op == TOKequal ? TOKidentity : TOKnotidentity),
+                    Token::toChars(e->op));
+                result = new ErrorExp();
+                return;
+            }
+            if (t1->ty == Tclass && t2->ty == Tnull ||
+                t1->ty == Tnull && t2->ty == Tclass)
+            {
+                // Comparing a class with typeof(null) should not call opEquals
+                return;
+            }
+
+            /* Check for class equality.
+             */
+            if (t1->ty == Tclass && t2->ty == Tclass)
+            {
+                ClassDeclaration *cd1 = t1->isClassHandle();
+                ClassDeclaration *cd2 = t2->isClassHandle();
+
+                if (!(cd1->cpp || cd2->cpp))
+                {
+                    /* Rewrite as:
+                     *      .object.opEquals(e1, e2)
+                     */
+                    Expression *e1x = e->e1;
+                    Expression *e2x = e->e2;
+
+                    /* The explicit cast is necessary for interfaces,
+                     * see Bugzilla 4088.
+                     */
+                    Type *to = ClassDeclaration::object->getType();
+                    if (cd1->isInterfaceDeclaration())
+                        e1x = new CastExp(e->loc, e->e1, t1->isMutable() ? to : to->constOf());
+                    if (cd2->isInterfaceDeclaration())
+                        e2x = new CastExp(e->loc, e->e2, t2->isMutable() ? to : to->constOf());
+
+                    result = new IdentifierExp(e->loc, Id::empty);
+                    result = new DotIdExp(e->loc, result, Id::object);
+                    result = new DotIdExp(e->loc, result, Id::eq);
+                    result = new CallExp(e->loc, result, e1x, e2x);
+                    if (e->op == TOKnotequal)
+                        result = new NotExp(e->loc, result);
+                    result = semantic(result, sc);
+                    return;
+                }
+            }
+
+            result = compare_overload(e, sc, Id::eq);
+            if (result)
+            {
+                if (result->op == TOKcall && e->op == TOKnotequal)
+                {
+                    result = new NotExp(result->loc, result);
+                    result = semantic(result, sc);
+                }
+                return;
+            }
+
+            /* Check for pointer equality.
+             */
+            if (t1->ty == Tpointer || t2->ty == Tpointer)
+            {
+                /* Rewrite:
+                 *      ptr1 == ptr2
+                 * as:
+                 *      ptr1 is ptr2
+                 *
+                 * This is just a rewriting for deterministic AST representation
+                 * as the backend input.
+                 */
+                TOK op2 = e->op == TOKequal ? TOKidentity : TOKnotidentity;
+                result = new IdentityExp(op2, e->loc, e->e1, e->e2);
+                result = semantic(result, sc);
+                return;
+            }
+
+            /* Check for struct equality without opEquals.
+             */
+            if (t1->ty == Tstruct && t2->ty == Tstruct)
+            {
+                StructDeclaration *sd = ((TypeStruct *)t1)->sym;
+                if (sd != ((TypeStruct *)t2)->sym)
+                    return;
+
+                if (!needOpEquals(sd))
+                {
+                    // Use bitwise equality.
+                    TOK op2 = e->op == TOKequal ? TOKidentity : TOKnotidentity;
+                    result = new IdentityExp(op2, e->loc, e->e1, e->e2);
+                    result = semantic(result, sc);
+                    return;
+                }
+
+                /* Do memberwise equality.
+                 * Rewrite:
+                 *      e1 == e2
+                 * as:
+                 *      e1.tupleof == e2.tupleof
+                 *
+                 * If sd is a nested struct, and if it's nested in a class, it will
+                 * also compare the parent class's equality. Otherwise, compares
+                 * the identity of parent context through void*.
+                 */
+                if (e->att1 && t1 == e->att1)
+                    return;
+                if (e->att2 && t2 == e->att2)
+                    return;
+
+                e = (EqualExp *)e->copy();
+                if (!e->att1)
+                    e->att1 = t1;
+                if (!e->att2)
+                    e->att2 = t2;
+                e->e1 = new DotIdExp(e->loc, e->e1, Id::_tupleof);
+                e->e2 = new DotIdExp(e->loc, e->e2, Id::_tupleof);
+                result = semantic(e, sc);
+
+                /* Bugzilla 15292, if the rewrite result is same with the original,
+                 * the equality is unresolvable because it has recursive definition.
+                 */
+                if (result->op == e->op &&
+                    ((EqualExp *)result)->e1->type->toBasetype() == t1)
+                {
+                    e->error("cannot compare %s because its auto generated member-wise equality has recursive definition",
+                        t1->toChars());
+                    result = new ErrorExp();
+                }
+                return;
+            }
+
+            /* Check for tuple equality.
+             */
+            if (e->e1->op == TOKtuple && e->e2->op == TOKtuple)
+            {
+                TupleExp *tup1 = (TupleExp *)e->e1;
+                TupleExp *tup2 = (TupleExp *)e->e2;
+                size_t dim = tup1->exps->dim;
+                if (dim != tup2->exps->dim)
+                {
+                    e->error("mismatched tuple lengths, %d and %d",
+                        (int)dim, (int)tup2->exps->dim);
+                    result = new ErrorExp();
+                    return;
+                }
+
+                if (dim == 0)
+                {
+                    // zero-length tuple comparison should always return true or false.
+                    result = new IntegerExp(e->loc, (e->op == TOKequal), Type::tbool);
+                }
+                else
+                {
+                    for (size_t i = 0; i < dim; i++)
+                    {
+                        Expression *ex1 = (*tup1->exps)[i];
+                        Expression *ex2 = (*tup2->exps)[i];
+                        EqualExp *eeq = new EqualExp(e->op, e->loc, ex1, ex2);
+                        eeq->att1 = e->att1;
+                        eeq->att2 = e->att2;
+
+                        if (!result)
+                            result = eeq;
+                        else if (e->op == TOKequal)
+                            result = new AndAndExp(e->loc, result, eeq);
+                        else
+                            result = new OrOrExp(e->loc, result, eeq);
+                    }
+                    assert(result);
+                }
+                result = Expression::combine(Expression::combine(tup1->e0, tup2->e0), result);
+                result = semantic(result, sc);
+                return;
+            }
+        }
+
+        void visit(CmpExp *e)
+        {
+            //printf("CmpExp::op_overload() (%s)\n", e->toChars());
+
+            result = compare_overload(e, sc, Id::cmp);
+        }
+
+        /*********************************
+         * Operator overloading for op=
+         */
+        void visit(BinAssignExp *e)
+        {
+            //printf("BinAssignExp::op_overload() (%s)\n", e->toChars());
+
+            if (e->e1->op == TOKarray)
+            {
+                ArrayExp *ae = (ArrayExp *)e->e1;
+                ae->e1 = semantic(ae->e1, sc);
+                ae->e1 = resolveProperties(sc, ae->e1);
+                Expression *ae1old = ae->e1;
+
+                const bool maybeSlice =
+                    (ae->arguments->dim == 0 ||
+                     ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval);
+                IntervalExp *ie = NULL;
+                if (maybeSlice && ae->arguments->dim)
+                {
+                    assert((*ae->arguments)[0]->op == TOKinterval);
+                    ie = (IntervalExp *)(*ae->arguments)[0];
+                }
+
+                while (true)
+                {
+                    if (ae->e1->op == TOKerror)
+                    {
+                        result = ae->e1;
+                        return;
+                    }
+                    Expression *e0 = NULL;
+                    Expression *ae1save = ae->e1;
+                    ae->lengthVar = NULL;
+
+                    Type *t1b = ae->e1->type->toBasetype();
+                    AggregateDeclaration *ad = isAggregate(t1b);
+                    if (!ad)
+                        break;
+                    if (search_function(ad, Id::opIndexOpAssign))
+                    {
+                        // Deal with $
+                        result = resolveOpDollar(sc, ae, &e0);
+                        if (!result)    // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j)
+                            goto Lfallback;
+                        if (result->op == TOKerror)
+                            return;
+
+                        result = semantic(e->e2, sc);
+                        if (result->op == TOKerror)
+                            return;
+                        e->e2 = result;
+
+                        /* Rewrite a[arguments] op= e2 as:
+                         *      a.opIndexOpAssign!(op)(e2, arguments)
+                         */
+                        Expressions *a = (Expressions *)ae->arguments->copy();
+                        a->insert(0, e->e2);
+                        Objects *tiargs = opToArg(sc, e->op);
+                        result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opIndexOpAssign, tiargs);
+                        result = new CallExp(e->loc, result, a);
+                        if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2)
+                            result = trySemantic(result, sc);
+                        else
+                            result = semantic(result, sc);
+                        if (result)
+                        {
+                            result = Expression::combine(e0, result);
+                            return;
+                        }
+                    }
+                Lfallback:
+                    if (maybeSlice && search_function(ad, Id::opSliceOpAssign))
+                    {
+                        // Deal with $
+                        result = resolveOpDollar(sc, ae, ie, &e0);
+                        if (result->op == TOKerror)
+                            return;
+
+                        result = semantic(e->e2, sc);
+                        if (result->op == TOKerror)
+                            return;
+                        e->e2 = result;
+
+                        /* Rewrite (a[i..j] op= e2) as:
+                         *      a.opSliceOpAssign!(op)(e2, i, j)
+                         */
+                        Expressions *a = new Expressions();
+                        a->push(e->e2);
+                        if (ie)
+                        {
+                            a->push(ie->lwr);
+                            a->push(ie->upr);
+                        }
+                        Objects *tiargs = opToArg(sc, e->op);
+                        result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opSliceOpAssign, tiargs);
+                        result = new CallExp(e->loc, result, a);
+                        result = semantic(result, sc);
+                        result = Expression::combine(e0, result);
+                        return;
+                    }
+
+                    // Didn't find it. Forward to aliasthis
+                    if (ad->aliasthis && t1b != ae->att1)
+                    {
+                        if (!ae->att1 && t1b->checkAliasThisRec())
+                            ae->att1 = t1b;
+
+                        /* Rewrite (a[arguments] op= e2) as:
+                         *      a.aliasthis[arguments] op= e2
+                         */
+                        ae->e1 = resolveAliasThis(sc, ae1save, true);
+                        if (ae->e1)
+                            continue;
+                    }
+                    break;
+                }
+                ae->e1 = ae1old;    // recovery
+                ae->lengthVar = NULL;
+            }
+
+            result = binSemanticProp(e, sc);
+            if (result)
+                return;
+
+            // Don't attempt 'alias this' if an error occured
+            if (e->e1->type->ty == Terror || e->e2->type->ty == Terror)
+            {
+                result = new ErrorExp();
+                return;
+            }
+
+            Identifier *id = opId(e);
+
+            Expressions args2;
+
+            AggregateDeclaration *ad1 = isAggregate(e->e1->type);
+
+            Dsymbol *s = NULL;
+
+        #if 1 // the old D1 scheme
+            if (ad1 && id)
+            {
+                s = search_function(ad1, id);
+            }
+        #endif
+
+            Objects *tiargs = NULL;
+            if (!s)
+            {
+                /* Try the new D2 scheme, opOpAssign
+                 */
+                if (ad1)
+                {
+                    s = search_function(ad1, Id::opOpAssign);
+                    if (s && !s->isTemplateDeclaration())
+                    {
+                        e->error("%s.opOpAssign isn't a template", e->e1->toChars());
+                        result = new ErrorExp();
+                        return;
+                    }
+                }
+
+                // Set tiargs, the template argument list, which will be the operator string
+                if (s)
+                {
+                    id = Id::opOpAssign;
+                    tiargs = opToArg(sc, e->op);
+                }
+            }
+
+            if (s)
+            {
+                /* Try:
+                 *      a.opOpAssign(b)
+                 */
+
+                args2.setDim(1);
+                args2[0] = e->e2;
+                expandTuples(&args2);
+
+                Match m;
+                memset(&m, 0, sizeof(m));
+                m.last = MATCHnomatch;
+
+                if (s)
+                {
+                    functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2);
+                    if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+                    {
+                        result = new ErrorExp();
+                        return;
+                    }
+                }
+
+                if (m.count > 1)
+                {
+                    // Error, ambiguous
+                    e->error("overloads %s and %s both match argument list for %s",
+                            m.lastf->type->toChars(),
+                            m.nextf->type->toChars(),
+                            m.lastf->toChars());
+                }
+                else if (m.last <= MATCHnomatch)
+                {
+                    m.lastf = m.anyf;
+                    if (tiargs)
+                        goto L1;
+                }
+
+                // Rewrite (e1 op e2) as e1.opOpAssign(e2)
+                result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s);
+                return;
+            }
+
+        L1:
+
+            // Try alias this on first operand
+            if (ad1 && ad1->aliasthis)
+            {
+                /* Rewrite (e1 op e2) as:
+                 *      (e1.aliasthis op e2)
+                 */
+                if (e->att1 && e->e1->type == e->att1)
+                    return;
+                //printf("att %s e1 = %s\n", Token::toChars(e->op), e->e1->type->toChars());
+                Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident);
+                BinExp *be = (BinExp *)e->copy();
+                if (!be->att1 && e->e1->type->checkAliasThisRec())
+                    be->att1 = e->e1->type;
+                be->e1 = e1;
+                result = trySemantic(be, sc);
+                return;
+            }
+
+            // Try alias this on second operand
+            AggregateDeclaration *ad2 = isAggregate(e->e2->type);
+            if (ad2 && ad2->aliasthis)
+            {
+                /* Rewrite (e1 op e2) as:
+                 *      (e1 op e2.aliasthis)
+                 */
+                if (e->att2 && e->e2->type == e->att2)
+                    return;
+                //printf("att %s e2 = %s\n", Token::toChars(e->op), e->e2->type->toChars());
+                Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident);
+                BinExp *be = (BinExp *)e->copy();
+                if (!be->att2 && e->e2->type->checkAliasThisRec())
+                    be->att2 = e->e2->type;
+                be->e2 = e2;
+                result = trySemantic(be, sc);
+                return;
+            }
+        }
+    };
+
+    OpOverload v(sc);
+    e->accept(&v);
+    return v.result;
+}
+
+/******************************************
+ * Common code for overloading of EqualExp and CmpExp
+ */
+Expression *compare_overload(BinExp *e, Scope *sc, Identifier *id)
+{
+    //printf("BinExp::compare_overload(id = %s) %s\n", id->toChars(), e->toChars());
+
+    AggregateDeclaration *ad1 = isAggregate(e->e1->type);
+    AggregateDeclaration *ad2 = isAggregate(e->e2->type);
+
+    Dsymbol *s = NULL;
+    Dsymbol *s_r = NULL;
+
+    if (ad1)
+    {
+        s = search_function(ad1, id);
+    }
+    if (ad2)
+    {
+        s_r = search_function(ad2, id);
+        if (s == s_r)
+            s_r = NULL;
+    }
+
+    Objects *tiargs = NULL;
+
+    if (s || s_r)
+    {
+        /* Try:
+         *      a.opEquals(b)
+         *      b.opEquals(a)
+         * and see which is better.
+         */
+
+        Expressions args1;
+        Expressions args2;
+
+        args1.setDim(1);
+        args1[0] = e->e1;
+        expandTuples(&args1);
+        args2.setDim(1);
+        args2[0] = e->e2;
+        expandTuples(&args2);
+
+        Match m;
+        memset(&m, 0, sizeof(m));
+        m.last = MATCHnomatch;
+
+        if (0 && s && s_r)
+        {
+            printf("s  : %s\n", s->toPrettyChars());
+            printf("s_r: %s\n", s_r->toPrettyChars());
+        }
+
+        if (s)
+        {
+            functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2);
+            if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+                return new ErrorExp();
+        }
+
+        FuncDeclaration *lastf = m.lastf;
+        int count = m.count;
+
+        if (s_r)
+        {
+            functionResolve(&m, s_r, e->loc, sc, tiargs, e->e2->type, &args1);
+            if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+                return new ErrorExp();
+        }
+
+        if (m.count > 1)
+        {
+            /* The following if says "not ambiguous" if there's one match
+             * from s and one from s_r, in which case we pick s.
+             * This doesn't follow the spec, but is a workaround for the case
+             * where opEquals was generated from templates and we cannot figure
+             * out if both s and s_r came from the same declaration or not.
+             * The test case is:
+             *   import std.typecons;
+             *   void main() {
+             *    assert(tuple("has a", 2u) == tuple("has a", 1));
+             *   }
+             */
+            if (!(m.lastf == lastf && m.count == 2 && count == 1))
+            {
+                // Error, ambiguous
+                e->error("overloads %s and %s both match argument list for %s",
+                    m.lastf->type->toChars(),
+                    m.nextf->type->toChars(),
+                    m.lastf->toChars());
+            }
+        }
+        else if (m.last <= MATCHnomatch)
+        {
+            m.lastf = m.anyf;
+        }
+
+        Expression *result;
+        if (lastf && m.lastf == lastf || !s_r && m.last <= MATCHnomatch)
+        {
+            // Rewrite (e1 op e2) as e1.opfunc(e2)
+            result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s);
+        }
+        else
+        {
+            // Rewrite (e1 op e2) as e2.opfunc_r(e1)
+            result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s_r);
+
+            // When reversing operands of comparison operators,
+            // need to reverse the sense of the op
+            switch (e->op)
+            {
+                case TOKlt:     e->op = TOKgt;     break;
+                case TOKgt:     e->op = TOKlt;     break;
+                case TOKle:     e->op = TOKge;     break;
+                case TOKge:     e->op = TOKle;     break;
+
+                // The rest are symmetric
+                default:
+                    break;
+            }
+        }
+
+        return result;
+    }
+
+    // Try alias this on first operand
+    if (ad1 && ad1->aliasthis)
+    {
+        /* Rewrite (e1 op e2) as:
+         *      (e1.aliasthis op e2)
+         */
+        if (e->att1 && e->e1->type == e->att1)
+            return NULL;
+        //printf("att cmp_bin e1 = %s\n", e->e1->type->toChars());
+        Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident);
+        BinExp *be = (BinExp *)e->copy();
+        if (!be->att1 && e->e1->type->checkAliasThisRec())
+            be->att1 = e->e1->type;
+        be->e1 = e1;
+        return trySemantic(be, sc);
+    }
+
+    // Try alias this on second operand
+    if (ad2 && ad2->aliasthis)
+    {
+        /* Rewrite (e1 op e2) as:
+         *      (e1 op e2.aliasthis)
+         */
+        if (e->att2 && e->e2->type == e->att2)
+            return NULL;
+        //printf("att cmp_bin e2 = %s\n", e->e2->type->toChars());
+        Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident);
+        BinExp *be = (BinExp *)e->copy();
+        if (!be->att2 && e->e2->type->checkAliasThisRec())
+            be->att2 = e->e2->type;
+        be->e2 = e2;
+        return trySemantic(be, sc);
+    }
+
+    return NULL;
+}
+
+/***********************************
+ * Utility to build a function call out of this reference and argument.
+ */
+
+Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg,
+        Dsymbol *d)
+{
+    assert(d);
+    Expression *e;
+
+    //printf("build_overload(id = '%s')\n", id->toChars());
+    //earg->print();
+    //earg->type->print();
+    Declaration *decl = d->isDeclaration();
+    if (decl)
+        e = new DotVarExp(loc, ethis, decl, false);
+    else
+        e = new DotIdExp(loc, ethis, d->ident);
+    e = new CallExp(loc, e, earg);
+
+    e = semantic(e, sc);
+    return e;
+}
+
+/***************************************
+ * Search for function funcid in aggregate ad.
+ */
+
+Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid)
+{
+    Dsymbol *s = ad->search(Loc(), funcid);
+    if (s)
+    {
+        //printf("search_function: s = '%s'\n", s->kind());
+        Dsymbol *s2 = s->toAlias();
+        //printf("search_function: s2 = '%s'\n", s2->kind());
+        FuncDeclaration *fd = s2->isFuncDeclaration();
+        if (fd && fd->type->ty == Tfunction)
+            return fd;
+
+        TemplateDeclaration *td = s2->isTemplateDeclaration();
+        if (td)
+            return td;
+    }
+    return NULL;
+}
+
+
+bool inferAggregate(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply)
+{
+    //printf("inferAggregate(%s)\n", fes->aggr->toChars());
+    Identifier *idapply = (fes->op == TOKforeach) ? Id::apply : Id::applyReverse;
+    Identifier *idfront = (fes->op == TOKforeach) ? Id::Ffront : Id::Fback;
+    int sliced = 0;
+    Type *tab;
+    Type *att = NULL;
+    Expression *aggr = fes->aggr;
+    AggregateDeclaration *ad;
+
+    while (1)
+    {
+        aggr = semantic(aggr, sc);
+        aggr = resolveProperties(sc, aggr);
+        aggr = aggr->optimize(WANTvalue);
+        if (!aggr->type || aggr->op == TOKerror)
+            goto Lerr;
+
+        tab = aggr->type->toBasetype();
+        switch (tab->ty)
+        {
+            case Tarray:
+            case Tsarray:
+            case Ttuple:
+            case Taarray:
+                break;
+
+            case Tclass:
+                ad = ((TypeClass *)tab)->sym;
+                goto Laggr;
+
+            case Tstruct:
+                ad = ((TypeStruct *)tab)->sym;
+                goto Laggr;
+
+            Laggr:
+                if (!sliced)
+                {
+                    sapply = search_function(ad, idapply);
+                    if (sapply)
+                    {
+                        // opApply aggregate
+                        break;
+                    }
+
+                    if (fes->aggr->op != TOKtype)
+                    {
+                        Expression *rinit = new ArrayExp(fes->aggr->loc, fes->aggr);
+                        rinit = trySemantic(rinit, sc);
+                        if (rinit)                  // if application of [] succeeded
+                        {
+                            aggr = rinit;
+                            sliced = 1;
+                            continue;
+                        }
+                    }
+                }
+
+                if (ad->search(Loc(), idfront))
+                {
+                    // range aggregate
+                    break;
+                }
+
+                if (ad->aliasthis)
+                {
+                    if (att == tab)
+                        goto Lerr;
+                    if (!att && tab->checkAliasThisRec())
+                        att = tab;
+                    aggr = resolveAliasThis(sc, aggr);
+                    continue;
+                }
+                goto Lerr;
+
+            case Tdelegate:
+                if (aggr->op == TOKdelegate)
+                {
+                    sapply = ((DelegateExp *)aggr)->func;
+                }
+                break;
+
+            case Terror:
+                break;
+
+            default:
+                goto Lerr;
+        }
+        break;
+    }
+    fes->aggr = aggr;
+    return true;
+
+Lerr:
+    return false;
+}
+
+/*****************************************
+ * Given array of parameters and an aggregate type,
+ * if any of the parameter types are missing, attempt to infer
+ * them from the aggregate type.
+ */
+
+bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply)
+{
+    if (!fes->parameters || !fes->parameters->dim)
+        return false;
+
+    if (sapply)     // prefer opApply
+    {
+        for (size_t u = 0; u < fes->parameters->dim; u++)
+        {
+            Parameter *p = (*fes->parameters)[u];
+            if (p->type)
+            {
+                p->type = p->type->semantic(fes->loc, sc);
+                p->type = p->type->addStorageClass(p->storageClass);
+            }
+        }
+
+        Expression *ethis;
+        Type *tab = fes->aggr->type->toBasetype();
+        if (tab->ty == Tclass || tab->ty == Tstruct)
+            ethis = fes->aggr;
+        else
+        {   assert(tab->ty == Tdelegate && fes->aggr->op == TOKdelegate);
+            ethis = ((DelegateExp *)fes->aggr)->e1;
+        }
+
+        /* Look for like an
+         *  int opApply(int delegate(ref Type [, ...]) dg);
+         * overload
+         */
+        FuncDeclaration *fd = sapply->isFuncDeclaration();
+        if (fd)
+        {
+            sapply = inferApplyArgTypesX(ethis, fd, fes->parameters);
+        }
+        return sapply != NULL;
+    }
+
+    /* Return if no parameters need types.
+     */
+    for (size_t u = 0; u < fes->parameters->dim; u++)
+    {
+        Parameter *p = (*fes->parameters)[u];
+        if (!p->type)
+            break;
+    }
+
+    AggregateDeclaration *ad;
+
+    Parameter *p = (*fes->parameters)[0];
+    Type *taggr = fes->aggr->type;
+    assert(taggr);
+    Type *tab = taggr->toBasetype();
+    switch (tab->ty)
+    {
+        case Tarray:
+        case Tsarray:
+        case Ttuple:
+            if (fes->parameters->dim == 2)
+            {
+                if (!p->type)
+                {
+                    p->type = Type::tsize_t;    // key type
+                    p->type = p->type->addStorageClass(p->storageClass);
+                }
+                p = (*fes->parameters)[1];
+            }
+            if (!p->type && tab->ty != Ttuple)
+            {
+                p->type = tab->nextOf();        // value type
+                p->type = p->type->addStorageClass(p->storageClass);
+            }
+            break;
+
+        case Taarray:
+        {
+            TypeAArray *taa = (TypeAArray *)tab;
+
+            if (fes->parameters->dim == 2)
+            {
+                if (!p->type)
+                {
+                    p->type = taa->index;       // key type
+                    p->type = p->type->addStorageClass(p->storageClass);
+                    if (p->storageClass & STCref) // key must not be mutated via ref
+                        p->type = p->type->addMod(MODconst);
+                }
+                p = (*fes->parameters)[1];
+            }
+            if (!p->type)
+            {
+                p->type = taa->next;            // value type
+                p->type = p->type->addStorageClass(p->storageClass);
+            }
+            break;
+        }
+
+        case Tclass:
+            ad = ((TypeClass *)tab)->sym;
+            goto Laggr;
+
+        case Tstruct:
+            ad = ((TypeStruct *)tab)->sym;
+            goto Laggr;
+
+        Laggr:
+            if (fes->parameters->dim == 1)
+            {
+                if (!p->type)
+                {
+                    /* Look for a front() or back() overload
+                     */
+                    Identifier *id = (fes->op == TOKforeach) ? Id::Ffront : Id::Fback;
+                    Dsymbol *s = ad->search(Loc(), id);
+                    FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
+                    if (fd)
+                    {
+                        // Resolve inout qualifier of front type
+                        p->type = fd->type->nextOf();
+                        if (p->type)
+                        {
+                            p->type = p->type->substWildTo(tab->mod);
+                            p->type = p->type->addStorageClass(p->storageClass);
+                        }
+                    }
+                    else if (s && s->isTemplateDeclaration())
+                        ;
+                    else if (s && s->isDeclaration())
+                        p->type = ((Declaration *)s)->type;
+                    else
+                        break;
+                }
+                break;
+            }
+            break;
+
+        case Tdelegate:
+        {
+            if (!inferApplyArgTypesY((TypeFunction *)tab->nextOf(), fes->parameters))
+                return false;
+            break;
+        }
+
+        default:
+            break;              // ignore error, caught later
+    }
+    return true;
+}
+
+static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *parameters)
+{
+  struct ParamOpOver
+  {
+    Parameters *parameters;
+    MOD mod;
+    MATCH match;
+    FuncDeclaration *fd_best;
+    FuncDeclaration *fd_ambig;
+
+    static int fp(void *param, Dsymbol *s)
+    {
+        FuncDeclaration *f = s->isFuncDeclaration();
+        if (!f)
+            return 0;
+        ParamOpOver *p = (ParamOpOver *)param;
+        TypeFunction *tf = (TypeFunction *)f->type;
+        MATCH m = MATCHexact;
+
+        if (f->isThis())
+        {
+            if (!MODimplicitConv(p->mod, tf->mod))
+                m = MATCHnomatch;
+            else if (p->mod != tf->mod)
+                m = MATCHconst;
+        }
+        if (!inferApplyArgTypesY(tf, p->parameters, 1))
+            m = MATCHnomatch;
+
+        if (m > p->match)
+        {
+            p->fd_best = f;
+            p->fd_ambig = NULL;
+            p->match = m;
+        }
+        else if (m == p->match)
+            p->fd_ambig = f;
+        return 0;
+    }
+  };
+    ParamOpOver p;
+    p.parameters = parameters;
+    p.mod = ethis->type->mod;
+    p.match = MATCHnomatch;
+    p.fd_best = NULL;
+    p.fd_ambig = NULL;
+    overloadApply(fstart, &p, &ParamOpOver::fp);
+    if (p.fd_best)
+    {
+        inferApplyArgTypesY((TypeFunction *)p.fd_best->type, parameters);
+        if (p.fd_ambig)
+        {   ::error(ethis->loc, "%s.%s matches more than one declaration:\n%s:     %s\nand:\n%s:     %s",
+                    ethis->toChars(), fstart->ident->toChars(),
+                    p.fd_best ->loc.toChars(), p.fd_best ->type->toChars(),
+                    p.fd_ambig->loc.toChars(), p.fd_ambig->type->toChars());
+            p.fd_best = NULL;
+        }
+    }
+    return p.fd_best;
+}
+
+/******************************
+ * Infer parameters from type of function.
+ * Returns:
+ *      1 match for this function
+ *      0 no match for this function
+ */
+
+static int inferApplyArgTypesY(TypeFunction *tf, Parameters *parameters, int flags)
+{   size_t nparams;
+    Parameter *p;
+
+    if (Parameter::dim(tf->parameters) != 1)
+        goto Lnomatch;
+    p = Parameter::getNth(tf->parameters, 0);
+    if (p->type->ty != Tdelegate)
+        goto Lnomatch;
+    tf = (TypeFunction *)p->type->nextOf();
+    assert(tf->ty == Tfunction);
+
+    /* We now have tf, the type of the delegate. Match it against
+     * the parameters, filling in missing parameter types.
+     */
+    nparams = Parameter::dim(tf->parameters);
+    if (nparams == 0 || tf->varargs)
+        goto Lnomatch;          // not enough parameters
+    if (parameters->dim != nparams)
+        goto Lnomatch;          // not enough parameters
+
+    for (size_t u = 0; u < nparams; u++)
+    {
+        p = (*parameters)[u];
+        Parameter *param = Parameter::getNth(tf->parameters, u);
+        if (p->type)
+        {
+            if (!p->type->equals(param->type))
+                goto Lnomatch;
+        }
+        else if (!flags)
+        {
+            p->type = param->type;
+            p->type = p->type->addStorageClass(p->storageClass);
+        }
+    }
+    return 1;
+
+Lnomatch:
+    return 0;
+}
+
diff --git a/gcc/d/dfrontend/optimize.c b/gcc/d/dfrontend/optimize.c
new file mode 100644
index 00000000000..348b667922c
--- /dev/null
+++ b/gcc/d/dfrontend/optimize.c
@@ -0,0 +1,1273 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/optimize.c
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <math.h>
+
+#include "checkedint.h"
+#include "lexer.h"
+#include "mtype.h"
+#include "expression.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "init.h"
+#include "enum.h"
+#include "ctfe.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+
+/*************************************
+ * If variable has a const initializer,
+ * return that initializer.
+ */
+
+Expression *expandVar(int result, VarDeclaration *v)
+{
+    //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v->toChars() : "null");
+
+    Expression *e = NULL;
+    if (!v)
+        return e;
+    if (!v->originalType && v->_scope)   // semantic() not yet run
+        v->semantic (v->_scope);
+
+    if (v->isConst() || v->isImmutable() || v->storage_class & STCmanifest)
+    {
+        if (!v->type)
+        {
+            return e;
+        }
+        Type *tb = v->type->toBasetype();
+        if (v->storage_class & STCmanifest ||
+            v->type->toBasetype()->isscalar() ||
+            ((result & WANTexpand) && (tb->ty != Tsarray && tb->ty != Tstruct))
+           )
+        {
+            if (v->_init)
+            {
+                if (v->inuse)
+                {
+                    if (v->storage_class & STCmanifest)
+                    {
+                        v->error("recursive initialization of constant");
+                        goto Lerror;
+                    }
+                    goto L1;
+                }
+                Expression *ei = v->getConstInitializer();
+                if (!ei)
+                {
+                    if (v->storage_class & STCmanifest)
+                    {
+                        v->error("enum cannot be initialized with %s", v->_init->toChars());
+                        goto Lerror;
+                    }
+                    goto L1;
+                }
+                if (ei->op == TOKconstruct || ei->op == TOKblit)
+                {
+                    AssignExp *ae = (AssignExp *)ei;
+                    ei = ae->e2;
+                    if (ei->isConst() == 1)
+                    {
+                    }
+                    else if (ei->op == TOKstring)
+                    {
+                        // Bugzilla 14459: We should not constfold the string literal
+                        // if it's typed as a C string, because the value expansion
+                        // will drop the pointer identity.
+                        if (!(result & WANTexpand) && ei->type->toBasetype()->ty == Tpointer)
+                            goto L1;
+                    }
+                    else
+                        goto L1;
+
+                    if (ei->type == v->type)
+                    {
+                        // const variable initialized with const expression
+                    }
+                    else if (ei->implicitConvTo(v->type) >= MATCHconst)
+                    {
+                        // const var initialized with non-const expression
+                        ei = ei->implicitCastTo(NULL, v->type);
+                        ei = semantic(ei, NULL);
+                    }
+                    else
+                        goto L1;
+                }
+                else if (!(v->storage_class & STCmanifest) &&
+                         ei->isConst() != 1 && ei->op != TOKstring &&
+                         ei->op != TOKaddress)
+                {
+                    goto L1;
+                }
+                if (!ei->type)
+                {
+                    goto L1;
+                }
+                else
+                {
+                    // Should remove the copy() operation by
+                    // making all mods to expressions copy-on-write
+                    e = ei->copy();
+                }
+            }
+            else
+            {
+#if 1
+                goto L1;
+#else
+                // BUG: what if const is initialized in constructor?
+                e = v->type->defaultInit();
+                e->loc = e1->loc;
+#endif
+            }
+            if (e->type != v->type)
+            {
+                e = e->castTo(NULL, v->type);
+            }
+            v->inuse++;
+            e = e->optimize(result);
+            v->inuse--;
+        }
+    }
+L1:
+    //if (e) printf("\te = %p, %s, e->type = %d, %s\n", e, e->toChars(), e->type->ty, e->type->toChars());
+    return e;
+
+Lerror:
+    return new ErrorExp();
+}
+
+
+Expression *fromConstInitializer(int result, Expression *e1)
+{
+    //printf("fromConstInitializer(result = %x, %s)\n", result, e1->toChars());
+    //static int xx; if (xx++ == 10) assert(0);
+    Expression *e = e1;
+    if (e1->op == TOKvar)
+    {
+        VarExp *ve = (VarExp *)e1;
+        VarDeclaration *v = ve->var->isVarDeclaration();
+        e = expandVar(result, v);
+        if (e)
+        {
+            // If it is a comma expression involving a declaration, we mustn't
+            // perform a copy -- we'd get two declarations of the same variable.
+            // See bugzilla 4465.
+            if (e->op == TOKcomma && ((CommaExp *)e)->e1->op == TOKdeclaration)
+                 e = e1;
+            else
+
+            if (e->type != e1->type && e1->type && e1->type->ty != Tident)
+            {
+                // Type 'paint' operation
+                e = e->copy();
+                e->type = e1->type;
+            }
+            e->loc = e1->loc;
+        }
+        else
+        {
+            e = e1;
+        }
+    }
+    return e;
+}
+
+Expression *Expression_optimize(Expression *e, int result, bool keepLvalue)
+{
+    class OptimizeVisitor : public Visitor
+    {
+    public:
+        int result;
+        bool keepLvalue;
+        Expression *ret;
+
+        OptimizeVisitor(int result, bool keepLvalue)
+            : result(result), keepLvalue(keepLvalue)
+        {
+        }
+
+        void error()
+        {
+            ret = new ErrorExp();
+        }
+
+        bool expOptimize(Expression *&e, int flags, bool keepLvalue = false)
+        {
+            if (!e)
+                return false;
+            Expression *ex = e->optimize(flags, keepLvalue);
+            if (ex->op == TOKerror)
+            {
+                ret = ex;   // store error result
+                return true;
+            }
+            else
+            {
+                e = ex;     // modify original
+                return false;
+            }
+        }
+
+        bool unaOptimize(UnaExp *e, int flags)
+        {
+            return expOptimize(e->e1, flags);
+        }
+
+        bool binOptimize(BinExp *e, int flags)
+        {
+            expOptimize(e->e1, flags);
+            expOptimize(e->e2, flags);
+            return ret->op == TOKerror;
+        }
+
+        void visit(Expression *e)
+        {
+            //printf("Expression::optimize(result = x%x) %s\n", result, e->toChars());
+        }
+
+        void visit(VarExp *e)
+        {
+            if (keepLvalue)
+            {
+                VarDeclaration *v = e->var->isVarDeclaration();
+                if (v && !(v->storage_class & STCmanifest))
+                    return;
+            }
+            ret = fromConstInitializer(result, e);
+        }
+
+        void visit(TupleExp *e)
+        {
+            expOptimize(e->e0, WANTvalue);
+            for (size_t i = 0; i < e->exps->dim; i++)
+            {
+                expOptimize((*e->exps)[i], WANTvalue);
+            }
+        }
+
+        void visit(ArrayLiteralExp *e)
+        {
+            if (e->elements)
+            {
+                expOptimize(e->basis, result & WANTexpand);
+                for (size_t i = 0; i < e->elements->dim; i++)
+                {
+                    expOptimize((*e->elements)[i], result & WANTexpand);
+                }
+            }
+        }
+
+        void visit(AssocArrayLiteralExp *e)
+        {
+            assert(e->keys->dim == e->values->dim);
+            for (size_t i = 0; i < e->keys->dim; i++)
+            {
+                expOptimize((*e->keys)[i], result & WANTexpand);
+                expOptimize((*e->values)[i], result & WANTexpand);
+            }
+        }
+
+        void visit(StructLiteralExp *e)
+        {
+            if (e->stageflags & stageOptimize) return;
+            int old = e->stageflags;
+            e->stageflags |= stageOptimize;
+            if (e->elements)
+            {
+                for (size_t i = 0; i < e->elements->dim; i++)
+                {
+                    expOptimize((*e->elements)[i], result & WANTexpand);
+                }
+            }
+            e->stageflags = old;
+        }
+
+        void visit(UnaExp *e)
+        {
+            //printf("UnaExp::optimize() %s\n", e->toChars());
+            if (unaOptimize(e, result))
+                return;
+        }
+
+        void visit(NegExp *e)
+        {
+            if (unaOptimize(e, result))
+                return;
+
+            if (e->e1->isConst() == 1)
+            {
+                ret = Neg(e->type, e->e1).copy();
+            }
+        }
+
+        void visit(ComExp *e)
+        {
+            if (unaOptimize(e, result))
+                return;
+
+            if (e->e1->isConst() == 1)
+            {
+                ret = Com(e->type, e->e1).copy();
+            }
+        }
+
+        void visit(NotExp *e)
+        {
+            if (unaOptimize(e, result))
+                return;
+
+            if (e->e1->isConst() == 1)
+            {
+                ret = Not(e->type, e->e1).copy();
+            }
+        }
+
+        void visit(SymOffExp *e)
+        {
+            assert(e->var);
+        }
+
+        void visit(AddrExp *e)
+        {
+            //printf("AddrExp::optimize(result = %d) %s\n", result, e->toChars());
+
+            /* Rewrite &(a,b) as (a,&b)
+             */
+            if (e->e1->op == TOKcomma)
+            {
+                CommaExp *ce = (CommaExp *)e->e1;
+                AddrExp *ae = new AddrExp(e->loc, ce->e2);
+                ae->type = e->type;
+                ret = new CommaExp(ce->loc, ce->e1, ae);
+                ret->type = e->type;
+                return;
+            }
+
+            // Keep lvalue-ness
+            if (expOptimize(e->e1, result, true))
+                return;
+
+            // Convert &*ex to ex
+            if (e->e1->op == TOKstar)
+            {
+                Expression *ex = ((PtrExp *)e->e1)->e1;
+                if (e->type->equals(ex->type))
+                    ret = ex;
+                else if (e->type->toBasetype()->equivalent(ex->type->toBasetype()))
+                {
+                    ret = ex->copy();
+                    ret->type = e->type;
+                }
+                return;
+            }
+            if (e->e1->op == TOKvar)
+            {
+                VarExp *ve = (VarExp *)e->e1;
+                if (!ve->var->isOut() && !ve->var->isRef() &&
+                    !ve->var->isImportedSymbol())
+                {
+                    ret = new SymOffExp(e->loc, ve->var, 0, ve->hasOverloads);
+                    ret->type = e->type;
+                    return;
+                }
+            }
+            if (e->e1->op == TOKindex)
+            {
+                // Convert &array[n] to &array+n
+                IndexExp *ae = (IndexExp *)e->e1;
+
+                if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar)
+                {
+                    sinteger_t index = ae->e2->toInteger();
+                    VarExp *ve = (VarExp *)ae->e1;
+                    if (ve->type->ty == Tsarray
+                        && !ve->var->isImportedSymbol())
+                    {
+                        TypeSArray *ts = (TypeSArray *)ve->type;
+                        sinteger_t dim = ts->dim->toInteger();
+                        if (index < 0 || index >= dim)
+                        {
+                            e->error("array index %lld is out of bounds [0..%lld]", index, dim);
+                            return error();
+                        }
+
+                        bool overflow = false;
+                        const d_uns64 offset = mulu(index, ts->nextOf()->size(e->loc), overflow);
+                        if (overflow)
+                        {
+                            e->error("array offset overflow");
+                            return error();
+                        }
+
+                        ret = new SymOffExp(e->loc, ve->var, offset);
+                        ret->type = e->type;
+                        return;
+                    }
+                }
+            }
+        }
+
+        void visit(PtrExp *e)
+        {
+            //printf("PtrExp::optimize(result = x%x) %s\n", result, e->toChars());
+            if (expOptimize(e->e1, result))
+                return;
+            // Convert *&ex to ex
+            // But only if there is no type punning involved
+            if (e->e1->op == TOKaddress)
+            {
+                Expression *ex = ((AddrExp *)e->e1)->e1;
+                if (e->type->equals(ex->type))
+                    ret = ex;
+                else if (e->type->toBasetype()->equivalent(ex->type->toBasetype()))
+                {
+                    ret = ex->copy();
+                    ret->type = e->type;
+                }
+            }
+            if (keepLvalue)
+                return;
+
+            // Constant fold *(&structliteral + offset)
+            if (e->e1->op == TOKadd)
+            {
+                Expression *ex = Ptr(e->type, e->e1).copy();
+                if (!CTFEExp::isCantExp(ex))
+                {
+                    ret = ex;
+                    return;
+                }
+            }
+
+            if (e->e1->op == TOKsymoff)
+            {
+                SymOffExp *se = (SymOffExp *)e->e1;
+                VarDeclaration *v = se->var->isVarDeclaration();
+                Expression *ex = expandVar(result, v);
+                if (ex && ex->op == TOKstructliteral)
+                {
+                    StructLiteralExp *sle = (StructLiteralExp *)ex;
+                    ex = sle->getField(e->type, (unsigned)se->offset);
+                    if (ex && !CTFEExp::isCantExp(ex))
+                    {
+                        ret = ex;
+                        return;
+                    }
+                }
+            }
+        }
+
+        void visit(DotVarExp *e)
+        {
+            //printf("DotVarExp::optimize(result = x%x) %s\n", result, e->toChars());
+            if (expOptimize(e->e1, result))
+                return;
+            if (keepLvalue)
+                return;
+
+            Expression *ex = e->e1;
+
+            if (ex->op == TOKvar)
+            {
+                VarExp *ve = (VarExp *)ex;
+                VarDeclaration *v = ve->var->isVarDeclaration();
+                ex = expandVar(result, v);
+            }
+
+            if (ex && ex->op == TOKstructliteral)
+            {
+                StructLiteralExp *sle = (StructLiteralExp *)ex;
+                VarDeclaration *vf = e->var->isVarDeclaration();
+                if (vf && !vf->overlapped)
+                {
+                    /* Bugzilla 13021: Prevent optimization if vf has overlapped fields.
+                     */
+                    ex = sle->getField(e->type, vf->offset);
+                    if (ex && !CTFEExp::isCantExp(ex))
+                    {
+                        ret = ex;
+                        return;
+                    }
+                }
+            }
+        }
+
+        void visit(NewExp *e)
+        {
+            expOptimize(e->thisexp, WANTvalue);
+
+            // Optimize parameters
+            if (e->newargs)
+            {
+                for (size_t i = 0; i < e->newargs->dim; i++)
+                {
+                    expOptimize((*e->newargs)[i], WANTvalue);
+                }
+            }
+
+            if (e->arguments)
+            {
+                for (size_t i = 0; i < e->arguments->dim; i++)
+                {
+                    expOptimize((*e->arguments)[i], WANTvalue);
+                }
+            }
+        }
+
+        void visit(CallExp *e)
+        {
+            //printf("CallExp::optimize(result = %d) %s\n", result, e->toChars());
+
+            // Optimize parameters with keeping lvalue-ness
+            if (expOptimize(e->e1, result))
+                return;
+            if (e->arguments)
+            {
+                Type *t1 = e->e1->type->toBasetype();
+                if (t1->ty == Tdelegate) t1 = t1->nextOf();
+                assert(t1->ty == Tfunction);
+                TypeFunction *tf = (TypeFunction *)t1;
+                for (size_t i = 0; i < e->arguments->dim; i++)
+                {
+                    Parameter *p = Parameter::getNth(tf->parameters, i);
+                    bool keep = p && (p->storageClass & (STCref | STCout)) != 0;
+                    expOptimize((*e->arguments)[i], WANTvalue, keep);
+                }
+            }
+        }
+
+        void visit(CastExp *e)
+        {
+            //printf("CastExp::optimize(result = %d) %s\n", result, e->toChars());
+            //printf("from %s to %s\n", e->type->toChars(), e->to->toChars());
+            //printf("from %s\n", e->type->toChars());
+            //printf("e1->type %s\n", e->e1->type->toChars());
+            //printf("type = %p\n", e->type);
+            assert(e->type);
+            TOK op1 = e->e1->op;
+
+            Expression *e1old = e->e1;
+            if (expOptimize(e->e1, result))
+                return;
+            e->e1 = fromConstInitializer(result, e->e1);
+
+            if (e->e1 == e1old &&
+                e->e1->op == TOKarrayliteral &&
+                e->type->toBasetype()->ty == Tpointer &&
+                e->e1->type->toBasetype()->ty != Tsarray)
+            {
+                // Casting this will result in the same expression, and
+                // infinite loop because of Expression::implicitCastTo()
+                return;            // no change
+            }
+
+            if ((e->e1->op == TOKstring || e->e1->op == TOKarrayliteral) &&
+                (e->type->ty == Tpointer || e->type->ty == Tarray))
+            {
+                const d_uns64 esz = e->type->nextOf()->size(e->loc);
+                const d_uns64 e1sz = e->e1->type->toBasetype()->nextOf()->size(e->e1->loc);
+                if (esz == SIZE_INVALID || e1sz == SIZE_INVALID)
+                    return error();
+
+                if (e1sz == esz)
+                {
+                    // Bugzilla 12937: If target type is void array, trying to paint
+                    // e->e1 with that type will cause infinite recursive optimization.
+                    if (e->type->nextOf()->ty == Tvoid)
+                        return;
+
+                    ret = e->e1->castTo(NULL, e->type);
+                    //printf(" returning1 %s\n", ret->toChars());
+                    return;
+                }
+            }
+
+            if (e->e1->op == TOKstructliteral &&
+                e->e1->type->implicitConvTo(e->type) >= MATCHconst)
+            {
+                //printf(" returning2 %s\n", e->e1->toChars());
+            L1: // Returning e1 with changing its type
+                ret = (e1old == e->e1 ? e->e1->copy() : e->e1);
+                ret->type = e->type;
+                return;
+            }
+
+            /* The first test here is to prevent infinite loops
+             */
+            if (op1 != TOKarrayliteral && e->e1->op == TOKarrayliteral)
+            {
+                ret = e->e1->castTo(NULL, e->to);
+                return;
+            }
+            if (e->e1->op == TOKnull &&
+                (e->type->ty == Tpointer || e->type->ty == Tclass || e->type->ty == Tarray))
+            {
+                //printf(" returning3 %s\n", e->e1->toChars());
+                goto L1;
+            }
+
+            if (e->type->ty == Tclass && e->e1->type->ty == Tclass)
+            {
+                // See if we can remove an unnecessary cast
+                ClassDeclaration *cdfrom = e->e1->type->isClassHandle();
+                ClassDeclaration *cdto = e->type->isClassHandle();
+                // Need to determine correct offset before optimizing away the cast.
+                // https://issues.dlang.org/show_bug.cgi?id=16980
+                cdfrom->size(e->loc);
+                assert(cdfrom->sizeok == SIZEOKdone);
+                assert(cdto->sizeok == SIZEOKdone || !cdto->isBaseOf(cdfrom, NULL));
+                int offset;
+                if (cdto->isBaseOf(cdfrom, &offset) && offset == 0)
+                {
+                    //printf(" returning4 %s\n", e->e1->toChars());
+                    goto L1;
+                }
+            }
+
+            // We can convert 'head const' to mutable
+            if (e->to->mutableOf()->constOf()->equals(e->e1->type->mutableOf()->constOf()))
+            {
+                //printf(" returning5 %s\n", e->e1->toChars());
+                goto L1;
+            }
+
+            if (e->e1->isConst())
+            {
+                if (e->e1->op == TOKsymoff)
+                {
+                    if (e->type->toBasetype()->ty != Tsarray)
+                    {
+                        const d_uns64 esz = e->type->size(e->loc);
+                        const d_uns64 e1sz = e->e1->type->size(e->e1->loc);
+                        if (esz == SIZE_INVALID ||
+                            e1sz == SIZE_INVALID)
+                            return error();
+
+                        if (esz == e1sz)
+                            goto L1;
+                    }
+                    return;
+                }
+                if (e->to->toBasetype()->ty != Tvoid)
+                {
+                    if (e->e1->type->equals(e->type) && e->type->equals(e->to))
+                        ret = e->e1;
+                    else
+                        ret = Cast(e->type, e->to, e->e1).copy();
+                }
+            }
+            //printf(" returning6 %s\n", ret->toChars());
+        }
+
+        void visit(BinExp *e)
+        {
+            //printf("BinExp::optimize(result = %d) %s\n", result, e->toChars());
+            // don't replace const variable with its initializer in e1
+            bool e2only = (e->op == TOKconstruct || e->op == TOKblit);
+            if (e2only ? expOptimize(e->e2, result) : binOptimize(e, result))
+                return;
+
+            if (e->op == TOKshlass || e->op == TOKshrass || e->op == TOKushrass)
+            {
+                if (e->e2->isConst() == 1)
+                {
+                    sinteger_t i2 = e->e2->toInteger();
+                    d_uns64 sz = e->e1->type->size(e->e1->loc);
+                    assert(sz != SIZE_INVALID);
+                    sz *= 8;
+                    if (i2 < 0 || i2 >= sz)
+                    {
+                        e->error("shift assign by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1);
+                        return error();
+                    }
+                }
+            }
+        }
+
+        void visit(AddExp *e)
+        {
+            //printf("AddExp::optimize(%s)\n", e->toChars());
+
+            if (binOptimize(e, result))
+                return;
+
+            if (e->e1->isConst() && e->e2->isConst())
+            {
+                if (e->e1->op == TOKsymoff && e->e2->op == TOKsymoff)
+                    return;
+                ret = Add(e->type, e->e1, e->e2).copy();
+            }
+        }
+
+        void visit(MinExp *e)
+        {
+            if (binOptimize(e, result))
+                return;
+
+            if (e->e1->isConst() && e->e2->isConst())
+            {
+                if (e->e2->op == TOKsymoff)
+                    return;
+                ret = Min(e->type, e->e1, e->e2).copy();
+            }
+        }
+
+        void visit(MulExp *e)
+        {
+            //printf("MulExp::optimize(result = %d) %s\n", result, e->toChars());
+
+            if (binOptimize(e, result))
+                return;
+
+            if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+            {
+                ret = Mul(e->type, e->e1, e->e2).copy();
+            }
+        }
+
+        void visit(DivExp *e)
+        {
+            //printf("DivExp::optimize(%s)\n", e->toChars());
+
+            if (binOptimize(e, result))
+                return;
+
+            if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+            {
+                ret = Div(e->type, e->e1, e->e2).copy();
+            }
+        }
+
+        void visit(ModExp *e)
+        {
+            if (binOptimize(e, result))
+                return;
+
+            if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+            {
+                ret = Mod(e->type, e->e1, e->e2).copy();
+            }
+        }
+
+        void shift_optimize(BinExp *e, UnionExp (*shift)(Type *, Expression *, Expression *))
+        {
+            if (binOptimize(e, result))
+                return;
+
+            if (e->e2->isConst() == 1)
+            {
+                sinteger_t i2 = e->e2->toInteger();
+                d_uns64 sz = e->e1->type->size();
+                assert(sz != SIZE_INVALID);
+                sz *= 8;
+                if (i2 < 0 || i2 >= sz)
+                {
+                    e->error("shift by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1);
+                    return error();
+                }
+                if (e->e1->isConst() == 1)
+                    ret = (*shift)(e->type, e->e1, e->e2).copy();
+            }
+        }
+
+        void visit(ShlExp *e)
+        {
+            //printf("ShlExp::optimize(result = %d) %s\n", result, e->toChars());
+            shift_optimize(e, &Shl);
+        }
+
+        void visit(ShrExp *e)
+        {
+            //printf("ShrExp::optimize(result = %d) %s\n", result, e->toChars());
+            shift_optimize(e, &Shr);
+        }
+
+        void visit(UshrExp *e)
+        {
+            //printf("UshrExp::optimize(result = %d) %s\n", result, toChars());
+            shift_optimize(e, &Ushr);
+        }
+
+        void visit(AndExp *e)
+        {
+            if (binOptimize(e, result))
+                return;
+
+            if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+                ret = And(e->type, e->e1, e->e2).copy();
+        }
+
+        void visit(OrExp *e)
+        {
+            if (binOptimize(e, result))
+                return;
+
+            if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+                ret = Or(e->type, e->e1, e->e2).copy();
+        }
+
+        void visit(XorExp *e)
+        {
+            if (binOptimize(e, result))
+                return;
+
+            if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+                ret = Xor(e->type, e->e1, e->e2).copy();
+        }
+
+        void visit(PowExp *e)
+        {
+            if (binOptimize(e, result))
+                return;
+
+            // Replace 1 ^^ x or 1.0^^x by (x, 1)
+            if ((e->e1->op == TOKint64 && e->e1->toInteger() == 1) ||
+                (e->e1->op == TOKfloat64 && e->e1->toReal() == CTFloat::one))
+            {
+                ret = new CommaExp(e->loc, e->e2, e->e1);
+                ret->type = e->type;
+                return;
+            }
+
+            // Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral
+            if (e->e2->type->isintegral() && e->e1->op == TOKint64 && (sinteger_t)e->e1->toInteger() == -1L)
+            {
+                ret = new AndExp(e->loc, e->e2, new IntegerExp(e->loc, 1, e->e2->type));
+                ret->type = e->e2->type;
+                ret = new CondExp(e->loc, ret, new IntegerExp(e->loc, -1L, e->type), new IntegerExp(e->loc, 1L, e->type));
+                ret->type = e->type;
+                return;
+            }
+
+            // Replace x ^^ 0 or x^^0.0 by (x, 1)
+            if ((e->e2->op == TOKint64 && e->e2->toInteger() == 0) ||
+                (e->e2->op == TOKfloat64 && e->e2->toReal() == CTFloat::zero))
+            {
+                if (e->e1->type->isintegral())
+                    ret = new IntegerExp(e->loc, 1, e->e1->type);
+                else
+                    ret = new RealExp(e->loc, CTFloat::one, e->e1->type);
+
+                ret = new CommaExp(e->loc, e->e1, ret);
+                ret->type = e->type;
+                return;
+            }
+
+            // Replace x ^^ 1 or x^^1.0 by (x)
+            if ((e->e2->op == TOKint64 && e->e2->toInteger() == 1) ||
+                (e->e2->op == TOKfloat64 && e->e2->toReal() == CTFloat::one))
+            {
+                ret = e->e1;
+                return;
+            }
+
+            // Replace x ^^ -1.0 by (1.0 / x)
+            if ((e->e2->op == TOKfloat64 && e->e2->toReal() == CTFloat::minusone))
+            {
+                ret = new DivExp(e->loc, new RealExp(e->loc, CTFloat::one, e->e2->type), e->e1);
+                ret->type = e->type;
+                return;
+            }
+
+            // All other negative integral powers are illegal
+            if ((e->e1->type->isintegral()) && (e->e2->op == TOKint64) && (sinteger_t)e->e2->toInteger() < 0)
+            {
+                e->error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?",
+                      e->e1->type->toBasetype()->toChars(), e->e1->toChars(), e->e2->toChars());
+                return error();
+            }
+
+            // If e2 *could* have been an integer, make it one.
+            if (e->e2->op == TOKfloat64 && (e->e2->toReal() == ldouble((sinteger_t)e->e2->toReal())))
+                e->e2 = new IntegerExp(e->loc, e->e2->toInteger(), Type::tint64);
+
+            if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+            {
+                Expression *ex = Pow(e->type, e->e1, e->e2).copy();
+                if (!CTFEExp::isCantExp(ex))
+                {
+                    ret = ex;
+                    return;
+                }
+            }
+
+            // (2 ^^ n) ^^ p -> 1 << n * p
+            if (e->e1->op == TOKint64 && e->e1->toInteger() > 0 &&
+                !((e->e1->toInteger() - 1) & e->e1->toInteger()) &&
+                e->e2->type->isintegral() && e->e2->type->isunsigned())
+            {
+                dinteger_t i = e->e1->toInteger();
+                dinteger_t mul = 1;
+                while ((i >>= 1) > 1)
+                    mul++;
+                Expression *shift = new MulExp(e->loc, e->e2, new IntegerExp(e->loc, mul, e->e2->type));
+                shift->type = e->e2->type;
+                shift = shift->castTo(NULL, Type::tshiftcnt);
+                ret = new ShlExp(e->loc, new IntegerExp(e->loc, 1, e->e1->type), shift);
+                ret->type = e->type;
+                return;
+            }
+        }
+
+        void visit(CommaExp *e)
+        {
+            //printf("CommaExp::optimize(result = %d) %s\n", result, e->toChars());
+            // Comma needs special treatment, because it may
+            // contain compiler-generated declarations. We can interpret them, but
+            // otherwise we must NOT attempt to constant-fold them.
+            // In particular, if the comma returns a temporary variable, it needs
+            // to be an lvalue (this is particularly important for struct constructors)
+
+            expOptimize(e->e1, WANTvalue);
+            expOptimize(e->e2, result, keepLvalue);
+            if (ret->op == TOKerror)
+                return;
+
+            if (!e->e1 || e->e1->op == TOKint64 || e->e1->op == TOKfloat64 || !hasSideEffect(e->e1))
+            {
+                ret = e->e2;
+                if (ret)
+                    ret->type = e->type;
+            }
+
+            //printf("-CommaExp::optimize(result = %d) %s\n", result, e->e->toChars());
+        }
+
+        void visit(ArrayLengthExp *e)
+        {
+            //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, e->toChars());
+
+            if (unaOptimize(e, WANTexpand))
+                return;
+
+            // CTFE interpret static immutable arrays (to get better diagnostics)
+            if (e->e1->op == TOKvar)
+            {
+                VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
+                if (v && (v->storage_class & STCstatic) && (v->storage_class & STCimmutable) && v->_init)
+                {
+                    if (Expression *ci = v->getConstInitializer())
+                        e->e1 = ci;
+                }
+            }
+
+            if (e->e1->op == TOKstring || e->e1->op == TOKarrayliteral || e->e1->op == TOKassocarrayliteral ||
+                e->e1->type->toBasetype()->ty == Tsarray)
+            {
+                ret = ArrayLength(e->type, e->e1).copy();
+            }
+        }
+
+        void visit(EqualExp *e)
+        {
+            //printf("EqualExp::optimize(result = %x) %s\n", result, e->toChars());
+            if (binOptimize(e, WANTvalue))
+                return;
+
+            Expression *e1 = fromConstInitializer(result, e->e1);
+            Expression *e2 = fromConstInitializer(result, e->e2);
+            if (e1->op == TOKerror)
+            {
+                ret = e1;
+                return;
+            }
+            if (e2->op == TOKerror)
+            {
+                ret = e2;
+                return;
+            }
+
+            ret = Equal(e->op, e->type, e1, e2).copy();
+            if (CTFEExp::isCantExp(ret))
+                ret = e;
+        }
+
+        void visit(IdentityExp *e)
+        {
+            //printf("IdentityExp::optimize(result = %d) %s\n", result, e->toChars());
+
+            if (binOptimize(e, WANTvalue))
+                return;
+
+            if ((e->e1->isConst()     && e->e2->isConst()) ||
+                (e->e1->op == TOKnull && e->e2->op == TOKnull)
+                )
+            {
+                ret = Identity(e->op, e->type, e->e1, e->e2).copy();
+                if (CTFEExp::isCantExp(ret))
+                    ret = e;
+            }
+        }
+
+        /* It is possible for constant folding to change an array expression of
+         * unknown length, into one where the length is known.
+         * If the expression 'arr' is a literal, set lengthVar to be its length.
+         */
+        static void setLengthVarIfKnown(VarDeclaration *lengthVar, Expression *arr)
+        {
+            if (!lengthVar)
+                return;
+            if (lengthVar->_init && !lengthVar->_init->isVoidInitializer())
+                return; // we have previously calculated the length
+            size_t len;
+            if (arr->op == TOKstring)
+                len = ((StringExp *)arr)->len;
+            else if (arr->op == TOKarrayliteral)
+                len = ((ArrayLiteralExp *)arr)->elements->dim;
+            else
+            {
+                Type *t = arr->type->toBasetype();
+                if (t->ty == Tsarray)
+                    len = (size_t)((TypeSArray *)t)->dim->toInteger();
+                else
+                    return; // we don't know the length yet
+            }
+
+            Expression *dollar = new IntegerExp(Loc(), len, Type::tsize_t);
+            lengthVar->_init = new ExpInitializer(Loc(), dollar);
+            lengthVar->storage_class |= STCstatic | STCconst;
+        }
+
+        void visit(IndexExp *e)
+        {
+            //printf("IndexExp::optimize(result = %d) %s\n", result, e->toChars());
+            if (expOptimize(e->e1, result & WANTexpand))
+                return;
+
+            Expression *ex = fromConstInitializer(result, e->e1);
+
+            // We might know $ now
+            setLengthVarIfKnown(e->lengthVar, ex);
+
+            if (expOptimize(e->e2, WANTvalue))
+                return;
+            if (keepLvalue)
+                return;
+            ret = Index(e->type, ex, e->e2).copy();
+            if (CTFEExp::isCantExp(ret))
+                ret = e;
+        }
+
+        void visit(SliceExp *e)
+        {
+            //printf("SliceExp::optimize(result = %d) %s\n", result, e->toChars());
+            if (expOptimize(e->e1, result & WANTexpand))
+                return;
+            if (!e->lwr)
+            {
+                if (e->e1->op == TOKstring)
+                {
+                    // Convert slice of string literal into dynamic array
+                    Type *t = e->e1->type->toBasetype();
+                    if (Type *tn = t->nextOf())
+                        ret = e->e1->castTo(NULL, tn->arrayOf());
+                }
+            }
+            else
+            {
+                e->e1 = fromConstInitializer(result, e->e1);
+                // We might know $ now
+                setLengthVarIfKnown(e->lengthVar, e->e1);
+                expOptimize(e->lwr, WANTvalue);
+                expOptimize(e->upr, WANTvalue);
+                if (ret->op == TOKerror)
+                    return;
+                ret = Slice(e->type, e->e1, e->lwr, e->upr).copy();
+                if (CTFEExp::isCantExp(ret))
+                    ret = e;
+            }
+
+            // Bugzilla 14649: We need to leave the slice form so it might be
+            // a part of array operation.
+            // Assume that the backend codegen will handle the form `e[]`
+            // as an equal to `e` itself.
+            if (ret->op == TOKstring)
+            {
+                e->e1 = ret;
+                e->lwr = NULL;
+                e->upr = NULL;
+                ret = e;
+            }
+            //printf("-SliceExp::optimize() %s\n", ret->toChars());
+        }
+
+        void visit(AndAndExp *e)
+        {
+            //printf("AndAndExp::optimize(%d) %s\n", result, e->toChars());
+            if (expOptimize(e->e1, WANTvalue))
+                return;
+
+            if (e->e1->isBool(false))
+            {
+                // Replace with (e1, false)
+                ret = new IntegerExp(e->loc, 0, Type::tbool);
+                ret = Expression::combine(e->e1, ret);
+                if (e->type->toBasetype()->ty == Tvoid)
+                {
+                    ret = new CastExp(e->loc, ret, Type::tvoid);
+                    ret->type = e->type;
+                }
+                return;
+            }
+
+            if (expOptimize(e->e2, WANTvalue))
+                return;
+
+            if (e->e1->isConst())
+            {
+                if (e->e2->isConst())
+                {
+                    bool n1 = e->e1->isBool(true);
+                    bool n2 = e->e2->isBool(true);
+                    ret = new IntegerExp(e->loc, n1 && n2, e->type);
+                }
+                else if (e->e1->isBool(true))
+                {
+                    if (e->type->toBasetype()->ty == Tvoid)
+                        ret = e->e2;
+                    else
+                    {
+                        ret = new CastExp(e->loc, e->e2, e->type);
+                        ret->type = e->type;
+                    }
+                }
+            }
+        }
+
+        void visit(OrOrExp *e)
+        {
+            //printf("OrOrExp::optimize(%d) %s\n", result, e->toChars());
+            if (expOptimize(e->e1, WANTvalue))
+                return;
+
+            if (e->e1->isBool(true))
+            {
+                // Replace with (e1, true)
+                ret = new IntegerExp(e->loc, 1, Type::tbool);
+                ret = Expression::combine(e->e1, ret);
+                if (e->type->toBasetype()->ty == Tvoid)
+                {
+                    ret = new CastExp(e->loc, ret, Type::tvoid);
+                    ret->type = e->type;
+                }
+                return;
+            }
+
+            if (expOptimize(e->e2, WANTvalue))
+                return;
+
+            if (e->e1->isConst())
+            {
+                if (e->e2->isConst())
+                {
+                    bool n1 = e->e1->isBool(true);
+                    bool n2 = e->e2->isBool(true);
+                    ret = new IntegerExp(e->loc, n1 || n2, e->type);
+                }
+                else if (e->e1->isBool(false))
+                {
+                    if (e->type->toBasetype()->ty == Tvoid)
+                        ret = e->e2;
+                    else
+                    {
+                        ret = new CastExp(e->loc, e->e2, e->type);
+                        ret->type = e->type;
+                    }
+                }
+            }
+        }
+
+        void visit(CmpExp *e)
+        {
+            //printf("CmpExp::optimize() %s\n", e->toChars());
+            if (binOptimize(e, WANTvalue))
+                return;
+
+            Expression *e1 = fromConstInitializer(result, e->e1);
+            Expression *e2 = fromConstInitializer(result, e->e2);
+
+            ret = Cmp(e->op, e->type, e1, e2).copy();
+            if (CTFEExp::isCantExp(ret))
+                ret = e;
+        }
+
+        void visit(CatExp *e)
+        {
+            //printf("CatExp::optimize(%d) %s\n", result, e->toChars());
+
+            if (binOptimize(e, result))
+                return;
+
+            if (e->e1->op == TOKcat)
+            {
+                // Bugzilla 12798: optimize ((expr ~ str1) ~ str2)
+                CatExp *ce1 = (CatExp *)e->e1;
+                CatExp cex(e->loc, ce1->e2, e->e2);
+                cex.type = e->type;
+                Expression *ex = cex.optimize(result);
+                if (ex != &cex)
+                {
+                    e->e1 = ce1->e1;
+                    e->e2 = ex;
+                }
+            }
+
+            // optimize "str"[] -> "str"
+            if (e->e1->op == TOKslice)
+            {
+                SliceExp *se1 = (SliceExp *)e->e1;
+                if (se1->e1->op == TOKstring && !se1->lwr)
+                    e->e1 = se1->e1;
+            }
+            if (e->e2->op == TOKslice)
+            {
+                SliceExp *se2 = (SliceExp *)e->e2;
+                if (se2->e1->op == TOKstring && !se2->lwr)
+                    e->e2 = se2->e1;
+            }
+
+            ret = Cat(e->type, e->e1, e->e2).copy();
+            if (CTFEExp::isCantExp(ret))
+                ret = e;
+        }
+
+        void visit(CondExp *e)
+        {
+            if (expOptimize(e->econd, WANTvalue))
+                return;
+            if (e->econd->isBool(true))
+                ret = e->e1->optimize(result, keepLvalue);
+            else if (e->econd->isBool(false))
+                ret = e->e2->optimize(result, keepLvalue);
+            else
+            {
+                expOptimize(e->e1, result, keepLvalue);
+                expOptimize(e->e2, result, keepLvalue);
+            }
+        }
+    };
+
+    OptimizeVisitor v(result, keepLvalue);
+    Expression *ex = NULL;
+    v.ret = e;
+
+    // Optimize the expression until it can no longer be simplified.
+    while (ex != v.ret)
+    {
+        ex = v.ret;
+        ex->accept(&v);
+    }
+    return ex;
+}
diff --git a/gcc/d/dfrontend/outbuffer.c b/gcc/d/dfrontend/outbuffer.c
new file mode 100644
index 00000000000..14ee8a8d70e
--- /dev/null
+++ b/gcc/d/dfrontend/outbuffer.c
@@ -0,0 +1,402 @@
+
+/* Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/outbuffer.c
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if __sun
+#include <alloca.h>
+#endif
+
+#include "outbuffer.h"
+#include "object.h"
+
+char *OutBuffer::extractData()
+{
+    char *p;
+
+    p = (char *)data;
+    data = NULL;
+    offset = 0;
+    size = 0;
+    return p;
+}
+
+void OutBuffer::reserve(size_t nbytes)
+{
+    //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes);
+    if (size - offset < nbytes)
+    {
+        size = (offset + nbytes) * 2;
+        size = (size + 15) & ~15;
+        data = (unsigned char *)mem.xrealloc(data, size);
+    }
+}
+
+void OutBuffer::reset()
+{
+    offset = 0;
+}
+
+void OutBuffer::setsize(size_t size)
+{
+    offset = size;
+}
+
+void OutBuffer::write(const void *data, size_t nbytes)
+{
+    if (doindent && !notlinehead)
+    {
+        if (level)
+        {
+            reserve(level);
+            for (size_t i=0; i<level; i++)
+            {
+                this->data[offset] = '\t';
+                offset++;
+            }
+        }
+        notlinehead = 1;
+    }
+    reserve(nbytes);
+    memcpy(this->data + offset, data, nbytes);
+    offset += nbytes;
+}
+
+void OutBuffer::writebstring(utf8_t *string)
+{
+    write(string,*string + 1);
+}
+
+void OutBuffer::writestring(const char *string)
+{
+    write(string,strlen(string));
+}
+
+void OutBuffer::prependstring(const char *string)
+{
+    size_t len = strlen(string);
+    reserve(len);
+    memmove(data + len, data, offset);
+    memcpy(data, string, len);
+    offset += len;
+}
+
+void OutBuffer::writenl()
+{
+#if _WIN32
+    writeword(0x0A0D);          // newline is CR,LF on Microsoft OS's
+#else
+    writeByte('\n');
+#endif
+    if (doindent)
+        notlinehead = 0;
+}
+
+void OutBuffer::writeByte(unsigned b)
+{
+    if (doindent && !notlinehead
+        && b != '\n')
+    {
+        if (level)
+        {
+            reserve(level);
+            for (size_t i=0; i<level; i++)
+            {
+                this->data[offset] = '\t';
+                offset++;
+            }
+        }
+        notlinehead = 1;
+    }
+    reserve(1);
+    this->data[offset] = (unsigned char)b;
+    offset++;
+}
+
+void OutBuffer::writeUTF8(unsigned b)
+{
+    reserve(6);
+    if (b <= 0x7F)
+    {
+        this->data[offset] = (unsigned char)b;
+        offset++;
+    }
+    else if (b <= 0x7FF)
+    {
+        this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0);
+        this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80);
+        offset += 2;
+    }
+    else if (b <= 0xFFFF)
+    {
+        this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0);
+        this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+        this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80);
+        offset += 3;
+    }
+    else if (b <= 0x1FFFFF)
+    {
+        this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0);
+        this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
+        this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+        this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80);
+        offset += 4;
+    }
+    else if (b <= 0x3FFFFFF)
+    {
+        this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8);
+        this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
+        this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
+        this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+        this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80);
+        offset += 5;
+    }
+    else if (b <= 0x7FFFFFFF)
+    {
+        this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC);
+        this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80);
+        this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
+        this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
+        this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+        this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80);
+        offset += 6;
+    }
+    else
+        assert(0);
+}
+
+void OutBuffer::prependbyte(unsigned b)
+{
+    reserve(1);
+    memmove(data + 1, data, offset);
+    data[0] = (unsigned char)b;
+    offset++;
+}
+
+void OutBuffer::writewchar(unsigned w)
+{
+#if _WIN32
+    writeword(w);
+#else
+    write4(w);
+#endif
+}
+
+void OutBuffer::writeword(unsigned w)
+{
+#if _WIN32
+    unsigned newline = 0x0A0D;
+#else
+    unsigned newline = '\n';
+#endif
+    if (doindent && !notlinehead
+        && w != newline)
+    {
+        if (level)
+        {
+            reserve(level);
+            for (size_t i=0; i<level; i++)
+            {
+                this->data[offset] = '\t';
+                offset++;
+            }
+        }
+        notlinehead = 1;
+    }
+    reserve(2);
+    *(unsigned short *)(this->data + offset) = (unsigned short)w;
+    offset += 2;
+}
+
+void OutBuffer::writeUTF16(unsigned w)
+{
+    reserve(4);
+    if (w <= 0xFFFF)
+    {
+        *(unsigned short *)(this->data + offset) = (unsigned short)w;
+        offset += 2;
+    }
+    else if (w <= 0x10FFFF)
+    {
+        *(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0);
+        *(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00);
+        offset += 4;
+    }
+    else
+        assert(0);
+}
+
+void OutBuffer::write4(unsigned w)
+{
+#if _WIN32
+    bool notnewline = w != 0x000A000D;
+#else
+    bool notnewline = true;
+#endif
+    if (doindent && !notlinehead && notnewline)
+    {
+        if (level)
+        {
+            reserve(level);
+            for (size_t i=0; i<level; i++)
+            {
+                this->data[offset] = '\t';
+                offset++;
+            }
+        }
+        notlinehead = 1;
+    }
+    reserve(4);
+    *(unsigned *)(this->data + offset) = w;
+    offset += 4;
+}
+
+void OutBuffer::write(OutBuffer *buf)
+{
+    if (buf)
+    {   reserve(buf->offset);
+        memcpy(data + offset, buf->data, buf->offset);
+        offset += buf->offset;
+    }
+}
+
+void OutBuffer::write(RootObject *obj)
+{
+    if (obj)
+    {
+        writestring(obj->toChars());
+    }
+}
+
+void OutBuffer::fill0(size_t nbytes)
+{
+    reserve(nbytes);
+    memset(data + offset,0,nbytes);
+    offset += nbytes;
+}
+
+void OutBuffer::vprintf(const char *format, va_list args)
+{
+    int count;
+
+    if (doindent)
+        write(NULL, 0); // perform indent
+    unsigned psize = 128;
+    for (;;)
+    {
+        reserve(psize);
+#if _WIN32
+        count = _vsnprintf((char *)data + offset,psize,format,args);
+        if (count != -1)
+            break;
+        psize *= 2;
+#elif POSIX
+        va_list va;
+        va_copy(va, args);
+/*
+  The functions vprintf(), vfprintf(), vsprintf(), vsnprintf()
+  are equivalent to the functions printf(), fprintf(), sprintf(),
+  snprintf(), respectively, except that they are called with a
+  va_list instead of a variable number of arguments. These
+  functions do not call the va_end macro. Consequently, the value
+  of ap is undefined after the call. The application should call
+  va_end(ap) itself afterwards.
+ */
+        count = vsnprintf((char *)data + offset,psize,format,va);
+        va_end(va);
+        if (count == -1)
+            psize *= 2;
+        else if (count >= psize)
+            psize = count + 1;
+        else
+            break;
+#else
+        assert(0);
+#endif
+    }
+    offset += count;
+}
+
+void OutBuffer::printf(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    vprintf(format,ap);
+    va_end(ap);
+}
+
+void OutBuffer::bracket(char left, char right)
+{
+    reserve(2);
+    memmove(data + 1, data, offset);
+    data[0] = left;
+    data[offset + 1] = right;
+    offset += 2;
+}
+
+/******************
+ * Insert left at i, and right at j.
+ * Return index just past right.
+ */
+
+size_t OutBuffer::bracket(size_t i, const char *left, size_t j, const char *right)
+{
+    size_t leftlen = strlen(left);
+    size_t rightlen = strlen(right);
+    reserve(leftlen + rightlen);
+    insert(i, left, leftlen);
+    insert(j + leftlen, right, rightlen);
+    return j + leftlen + rightlen;
+}
+
+void OutBuffer::spread(size_t offset, size_t nbytes)
+{
+    reserve(nbytes);
+    memmove(data + offset + nbytes, data + offset,
+        this->offset - offset);
+    this->offset += nbytes;
+}
+
+/****************************************
+ * Returns: offset + nbytes
+ */
+
+size_t OutBuffer::insert(size_t offset, const void *p, size_t nbytes)
+{
+    spread(offset, nbytes);
+    memmove(data + offset, p, nbytes);
+    return offset + nbytes;
+}
+
+void OutBuffer::remove(size_t offset, size_t nbytes)
+{
+    memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes));
+    this->offset -= nbytes;
+}
+
+char *OutBuffer::peekString()
+{
+    if (!offset || data[offset-1] != '\0')
+    {
+        writeByte(0);
+        offset--; // allow appending more
+    }
+    return (char *)data;
+}
+
+char *OutBuffer::extractString()
+{
+    if (!offset || data[offset-1] != '\0')
+        writeByte(0);
+    return extractData();
+}
diff --git a/gcc/d/dfrontend/outbuffer.h b/gcc/d/dfrontend/outbuffer.h
new file mode 100644
index 00000000000..39eacbfdba4
--- /dev/null
+++ b/gcc/d/dfrontend/outbuffer.h
@@ -0,0 +1,85 @@
+
+/* Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/dlang/dmd/blob/master/src/root/outbuffer.h
+ */
+
+#ifndef OUTBUFFER_H
+#define OUTBUFFER_H
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+#include "port.h"
+#include "rmem.h"
+
+#if __DMC__
+#pragma once
+#endif
+
+class RootObject;
+
+struct OutBuffer
+{
+    unsigned char *data;
+    size_t offset;
+    size_t size;
+
+    int level;
+    bool doindent;
+private:
+    bool notlinehead;
+public:
+
+    OutBuffer()
+    {
+        data = NULL;
+        offset = 0;
+        size = 0;
+
+        doindent = 0;
+        level = 0;
+        notlinehead = 0;
+    }
+    ~OutBuffer()
+    {
+        mem.xfree(data);
+    }
+    char *extractData();
+
+    void reserve(size_t nbytes);
+    void setsize(size_t size);
+    void reset();
+    void write(const void *data, d_size_t nbytes);
+    void writebstring(utf8_t *string);
+    void writestring(const char *string);
+    void prependstring(const char *string);
+    void writenl();                     // write newline
+    void writeByte(unsigned b);
+    void writeUTF8(unsigned b);
+    void prependbyte(unsigned b);
+    void writewchar(unsigned w);
+    void writeword(unsigned w);
+    void writeUTF16(unsigned w);
+    void write4(unsigned w);
+    void write(OutBuffer *buf);
+    void write(RootObject *obj);
+    void fill0(size_t nbytes);
+    void vprintf(const char *format, va_list args);
+    void printf(const char *format, ...);
+    void bracket(char left, char right);
+    size_t bracket(size_t i, const char *left, size_t j, const char *right);
+    void spread(size_t offset, size_t nbytes);
+    size_t insert(size_t offset, const void *data, size_t nbytes);
+    void remove(size_t offset, size_t nbytes);
+    // Append terminating null if necessary and get view of internal buffer
+    char *peekString();
+    // Append terminating null if necessary and take ownership of data
+    char *extractString();
+};
+
+#endif
diff --git a/gcc/d/dfrontend/parse.c b/gcc/d/dfrontend/parse.c
new file mode 100644
index 00000000000..6c36a092b52
--- /dev/null
+++ b/gcc/d/dfrontend/parse.c
@@ -0,0 +1,8283 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/parse.c
+ */
+
+// This is the D parser
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>                     // strlen(),memcpy()
+
+#include "rmem.h"
+#include "lexer.h"
+#include "parse.h"
+#include "init.h"
+#include "attrib.h"
+#include "cond.h"
+#include "mtype.h"
+#include "template.h"
+#include "staticassert.h"
+#include "expression.h"
+#include "statement.h"
+#include "module.h"
+#include "dsymbol.h"
+#include "import.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "enum.h"
+#include "id.h"
+#include "version.h"
+#include "aliasthis.h"
+#include "nspace.h"
+#include "hdrgen.h"
+
+Expression *typeToExpression(Type *t);
+Expression *initializerToExpression(Initializer *i, Type *t = NULL);
+
+// How multiple declarations are parsed.
+// If 1, treat as C.
+// If 0, treat:
+//      int *p, i;
+// as:
+//      int* p;
+//      int* i;
+#define CDECLSYNTAX     0
+
+// Support C cast syntax:
+//      (type)(expression)
+#define CCASTSYNTAX     1
+
+// Support postfix C array declarations, such as
+//      int a[3][4];
+#define CARRAYDECL      1
+
+Parser::Parser(Module *module, const utf8_t *base, size_t length, bool doDocComment)
+    : Lexer(module ? module->srcfile->toChars() : NULL, base, 0, length, doDocComment, false)
+{
+    //printf("Parser::Parser()\n");
+    mod = module;
+    md = NULL;
+    linkage = LINKd;
+    endloc = Loc();
+    inBrackets = 0;
+    lookingForElse = Loc();
+    //nextToken();              // start up the scanner
+}
+
+/*********************
+ * Use this constructor for string mixins.
+ * Input:
+ *      loc     location in source file of mixin
+ */
+Parser::Parser(Loc loc, Module *module, const utf8_t *base, size_t length, bool doDocComment)
+    : Lexer(module ? module->srcfile->toChars() : NULL, base, 0, length, doDocComment, false)
+{
+    //printf("Parser::Parser()\n");
+    scanloc = loc;
+
+#ifndef IN_GCC
+    if (loc.filename)
+    {
+        /* Create a pseudo-filename for the mixin string, as it may not even exist
+         * in the source file.
+         */
+        char *filename = (char *)mem.xmalloc(strlen(loc.filename) + 7 + sizeof(loc.linnum) * 3 + 1);
+        sprintf(filename, "%s-mixin-%d", loc.filename, (int)loc.linnum);
+        scanloc.filename = filename;
+    }
+#endif
+
+    mod = module;
+    md = NULL;
+    linkage = LINKd;
+    endloc = Loc();
+    inBrackets = 0;
+    lookingForElse = Loc();
+    //nextToken();              // start up the scanner
+}
+
+Dsymbols *Parser::parseModule()
+{
+    const utf8_t *comment = token.blockComment;
+    bool isdeprecated = false;
+    Expression *msg = NULL;
+    Expressions *udas = NULL;
+    Dsymbols *decldefs;
+
+    Token *tk;
+    if (skipAttributes(&token, &tk) && tk->value == TOKmodule)
+    {
+        while (token.value != TOKmodule)
+        {
+            switch (token.value)
+            {
+                case TOKdeprecated:
+                {
+                    // deprecated (...) module ...
+                    if (isdeprecated)
+                    {
+                        error("there is only one deprecation attribute allowed for module declaration");
+                    }
+                    else
+                    {
+                        isdeprecated = true;
+                    }
+                    nextToken();
+                    if (token.value == TOKlparen)
+                    {
+                        check(TOKlparen);
+                        msg = parseAssignExp();
+                        check(TOKrparen);
+                    }
+                    break;
+                }
+                case TOKat:
+                {
+                    Expressions *exps = NULL;
+                    StorageClass stc = parseAttribute(&exps);
+
+                    if (stc == STCproperty || stc == STCnogc || stc == STCdisable ||
+                        stc == STCsafe || stc == STCtrusted || stc == STCsystem)
+                    {
+                        error("@%s attribute for module declaration is not supported", token.toChars());
+                    }
+                    else
+                    {
+                        udas = UserAttributeDeclaration::concat(udas, exps);
+                    }
+                    if (stc)
+                        nextToken();
+                    break;
+                }
+                default:
+                {
+                    error("'module' expected instead of %s", token.toChars());
+                    nextToken();
+                    break;
+                }
+            }
+        }
+    }
+
+    if (udas)
+    {
+        Dsymbols *a = new Dsymbols();
+        UserAttributeDeclaration *udad = new UserAttributeDeclaration(udas, a);
+        mod->userAttribDecl = udad;
+    }
+
+    // ModuleDeclation leads off
+    if (token.value == TOKmodule)
+    {
+        Loc loc = token.loc;
+
+        nextToken();
+        if (token.value != TOKidentifier)
+        {
+            error("identifier expected following module");
+            goto Lerr;
+        }
+        else
+        {
+            Identifiers *a = NULL;
+            Identifier *id;
+
+            id = token.ident;
+            while (nextToken() == TOKdot)
+            {
+                if (!a)
+                    a = new Identifiers();
+                a->push(id);
+                nextToken();
+                if (token.value != TOKidentifier)
+                {
+                    error("identifier expected following package");
+                    goto Lerr;
+                }
+                id = token.ident;
+            }
+
+            md = new ModuleDeclaration(loc, a, id);
+            md->isdeprecated = isdeprecated;
+            md->msg = msg;
+
+            if (token.value != TOKsemicolon)
+                error("';' expected following module declaration instead of %s", token.toChars());
+            nextToken();
+            addComment(mod, comment);
+        }
+    }
+
+    decldefs = parseDeclDefs(0);
+    if (token.value != TOKeof)
+    {
+        error(token.loc, "unrecognized declaration");
+        goto Lerr;
+    }
+    return decldefs;
+
+Lerr:
+    while (token.value != TOKsemicolon && token.value != TOKeof)
+        nextToken();
+    nextToken();
+    return new Dsymbols();
+}
+
+struct PrefixAttributes
+{
+    StorageClass storageClass;
+    Expression *depmsg;
+    LINK link;
+    Prot protection;
+    bool setAlignment;
+    Expression *ealign;
+    Expressions *udas;
+    const utf8_t *comment;
+
+    PrefixAttributes()
+        : storageClass(STCundefined),
+          depmsg(NULL),
+          link(LINKdefault),
+          protection(PROTundefined),
+          setAlignment(false),
+          ealign(NULL),
+          udas(NULL),
+          comment(NULL)
+    {
+    }
+};
+
+Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes *pAttrs)
+{
+    Dsymbol *lastDecl = NULL;   // used to link unittest to its previous declaration
+    if (!pLastDecl)
+        pLastDecl = &lastDecl;
+
+    LINK linksave = linkage;    // save global state
+
+    //printf("Parser::parseDeclDefs()\n");
+    Dsymbols *decldefs = new Dsymbols();
+    do
+    {
+        // parse result
+        Dsymbol *s = NULL;
+        Dsymbols *a = NULL;
+
+        PrefixAttributes attrs;
+        if (!once || !pAttrs)
+        {
+            pAttrs = &attrs;
+            pAttrs->comment = token.blockComment;
+        }
+        PROTKIND prot;
+        StorageClass stc;
+        Condition *condition;
+
+        linkage = linksave;
+
+        switch (token.value)
+        {
+            case TOKenum:
+            {
+                /* Determine if this is a manifest constant declaration,
+                 * or a conventional enum.
+                 */
+                Token *t = peek(&token);
+                if (t->value == TOKlcurly || t->value == TOKcolon)
+                    s = parseEnum();
+                else if (t->value != TOKidentifier)
+                    goto Ldeclaration;
+                else
+                {
+                    t = peek(t);
+                    if (t->value == TOKlcurly || t->value == TOKcolon ||
+                        t->value == TOKsemicolon)
+                        s = parseEnum();
+                    else
+                        goto Ldeclaration;
+                }
+                break;
+            }
+
+            case TOKimport:
+                a = parseImport();
+                // keep pLastDecl
+                break;
+
+            case TOKtemplate:
+                s = (Dsymbol *)parseTemplateDeclaration();
+                break;
+
+            case TOKmixin:
+            {
+                Loc loc = token.loc;
+                switch (peekNext())
+                {
+                    case TOKlparen:
+                    {
+                        // mixin(string)
+                        nextToken();
+                        check(TOKlparen, "mixin");
+                        Expression *e = parseAssignExp();
+                        check(TOKrparen);
+                        check(TOKsemicolon);
+                        s = new CompileDeclaration(loc, e);
+                        break;
+                    }
+                    case TOKtemplate:
+                        // mixin template
+                        nextToken();
+                        s = (Dsymbol *)parseTemplateDeclaration(true);
+                        break;
+
+                    default:
+                        s = parseMixin();
+                        break;
+                }
+                break;
+            }
+
+            case TOKwchar: case TOKdchar:
+            case TOKbool: case TOKchar:
+            case TOKint8: case TOKuns8:
+            case TOKint16: case TOKuns16:
+            case TOKint32: case TOKuns32:
+            case TOKint64: case TOKuns64:
+            case TOKint128: case TOKuns128:
+            case TOKfloat32: case TOKfloat64: case TOKfloat80:
+            case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+            case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+            case TOKvoid:
+            case TOKalias:
+            case TOKidentifier:
+            case TOKsuper:
+            case TOKtypeof:
+            case TOKdot:
+            case TOKvector:
+            case TOKstruct:
+            case TOKunion:
+            case TOKclass:
+            case TOKinterface:
+            Ldeclaration:
+                a = parseDeclarations(false, pAttrs, pAttrs->comment);
+                if (a && a->dim)
+                    *pLastDecl = (*a)[a->dim-1];
+                break;
+
+            case TOKthis:
+                if (peekNext() == TOKdot)
+                    goto Ldeclaration;
+                else
+                    s = parseCtor(pAttrs);
+                break;
+
+            case TOKtilde:
+                s = parseDtor(pAttrs);
+                break;
+
+            case TOKinvariant:
+            {
+                Token *t = peek(&token);
+                if (t->value == TOKlparen && peek(t)->value == TOKrparen ||
+                    t->value == TOKlcurly)
+                {
+                    // invariant {}
+                    // invariant() {}
+                    s = parseInvariant(pAttrs);
+                }
+                else
+                {
+                    error("invariant body expected, not '%s'", token.toChars());
+                    goto Lerror;
+                }
+                break;
+            }
+
+            case TOKunittest:
+                if (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration)
+                {
+                    s = parseUnitTest(pAttrs);
+                    if (*pLastDecl)
+                        (*pLastDecl)->ddocUnittest = (UnitTestDeclaration *)s;
+                }
+                else
+                {
+                    // Skip over unittest block by counting { }
+                    Loc loc = token.loc;
+                    int braces = 0;
+                    while (1)
+                    {
+                        nextToken();
+                        switch (token.value)
+                        {
+                            case TOKlcurly:
+                                ++braces;
+                                continue;
+
+                            case TOKrcurly:
+                                if (--braces)
+                                    continue;
+                                nextToken();
+                                break;
+
+                            case TOKeof:
+                                /* { */
+                                error(loc, "closing } of unittest not found before end of file");
+                                goto Lerror;
+
+                            default:
+                                continue;
+                        }
+                        break;
+                    }
+                    // Workaround 14894. Add an empty unittest declaration to keep
+                    // the number of symbols in this scope independent of -unittest.
+                    s = new UnitTestDeclaration(loc, token.loc, STCundefined, NULL);
+                }
+                break;
+
+            case TOKnew:
+                s = parseNew(pAttrs);
+                break;
+
+            case TOKdelete:
+                s = parseDelete(pAttrs);
+                break;
+
+            case TOKcolon:
+            case TOKlcurly:
+                error("declaration expected, not '%s'",token.toChars());
+                goto Lerror;
+
+            case TOKrcurly:
+            case TOKeof:
+                if (once)
+                    error("declaration expected, not '%s'", token.toChars());
+                return decldefs;
+
+            case TOKstatic:
+            {
+                TOK next = peekNext();
+                if (next == TOKthis)
+                    s = parseStaticCtor(pAttrs);
+                else if (next == TOKtilde)
+                    s = parseStaticDtor(pAttrs);
+                else if (next == TOKassert)
+                    s = parseStaticAssert();
+                else if (next == TOKif)
+                {
+                    condition = parseStaticIfCondition();
+                    Dsymbols *athen;
+                    if (token.value == TOKcolon)
+                        athen = parseBlock(pLastDecl);
+                    else
+                    {
+                        Loc lookingForElseSave = lookingForElse;
+                        lookingForElse = token.loc;
+                        athen = parseBlock(pLastDecl);
+                        lookingForElse = lookingForElseSave;
+                    }
+                    Dsymbols *aelse = NULL;
+                    if (token.value == TOKelse)
+                    {
+                        Loc elseloc = token.loc;
+                        nextToken();
+                        aelse = parseBlock(pLastDecl);
+                        checkDanglingElse(elseloc);
+                    }
+                    s = new StaticIfDeclaration(condition, athen, aelse);
+                }
+                else if (next == TOKimport)
+                {
+                    a = parseImport();
+                    // keep pLastDecl
+                }
+                else
+                {
+                    stc = STCstatic;
+                    goto Lstc;
+                }
+                break;
+            }
+
+            case TOKconst:
+                if (peekNext() == TOKlparen)
+                    goto Ldeclaration;
+                stc = STCconst;
+                goto Lstc;
+
+            case TOKimmutable:
+                if (peekNext() == TOKlparen)
+                    goto Ldeclaration;
+                stc = STCimmutable;
+                goto Lstc;
+
+            case TOKshared:
+            {
+                TOK next = peekNext();
+                if (next == TOKlparen)
+                    goto Ldeclaration;
+                if (next == TOKstatic)
+                {
+                    TOK next2 = peekNext2();
+                    if (next2 == TOKthis)
+                    {
+                        s = parseSharedStaticCtor(pAttrs);
+                        break;
+                    }
+                    if (next2 == TOKtilde)
+                    {
+                        s = parseSharedStaticDtor(pAttrs);
+                        break;
+                    }
+                }
+                stc = STCshared;
+                goto Lstc;
+            }
+
+            case TOKwild:
+                if (peekNext() == TOKlparen)
+                    goto Ldeclaration;
+                stc = STCwild;
+                goto Lstc;
+
+            case TOKfinal:        stc = STCfinal;        goto Lstc;
+            case TOKauto:         stc = STCauto;         goto Lstc;
+            case TOKscope:        stc = STCscope;        goto Lstc;
+            case TOKoverride:     stc = STCoverride;     goto Lstc;
+            case TOKabstract:     stc = STCabstract;     goto Lstc;
+            case TOKsynchronized: stc = STCsynchronized; goto Lstc;
+            case TOKnothrow:      stc = STCnothrow;      goto Lstc;
+            case TOKpure:         stc = STCpure;         goto Lstc;
+            case TOKref:          stc = STCref;          goto Lstc;
+            case TOKgshared:      stc = STCgshared;      goto Lstc;
+            //case TOKmanifest:   stc = STCmanifest;     goto Lstc;
+            case TOKat:
+            {
+                Expressions *exps = NULL;
+                stc = parseAttribute(&exps);
+                if (stc)
+                    goto Lstc;                  // it's a predefined attribute
+                // no redundant/conflicting check for UDAs
+                pAttrs->udas = UserAttributeDeclaration::concat(pAttrs->udas, exps);
+                goto Lautodecl;
+            }
+            Lstc:
+                pAttrs->storageClass = appendStorageClass(pAttrs->storageClass, stc);
+                nextToken();
+
+            Lautodecl:
+                Token *tk;
+
+                /* Look for auto initializers:
+                 *      storage_class identifier = initializer;
+                 *      storage_class identifier(...) = initializer;
+                 */
+                if (token.value == TOKidentifier &&
+                    skipParensIf(peek(&token), &tk) &&
+                    tk->value == TOKassign)
+                {
+                    a = parseAutoDeclarations(pAttrs->storageClass, pAttrs->comment);
+                    pAttrs->storageClass = STCundefined;
+                    if (a && a->dim)
+                        *pLastDecl = (*a)[a->dim-1];
+                    if (pAttrs->udas)
+                    {
+                        s = new UserAttributeDeclaration(pAttrs->udas, a);
+                        pAttrs->udas = NULL;
+                    }
+                    break;
+                }
+
+                /* Look for return type inference for template functions.
+                 */
+                if (token.value == TOKidentifier &&
+                    skipParens(peek(&token), &tk) &&
+                    skipAttributes(tk, &tk) &&
+                    (tk->value == TOKlparen ||
+                     tk->value == TOKlcurly ||
+                     tk->value == TOKin ||
+                     tk->value == TOKout ||
+                     tk->value == TOKbody)
+                   )
+                {
+                    a = parseDeclarations(true, pAttrs, pAttrs->comment);
+                    if (a && a->dim)
+                        *pLastDecl = (*a)[a->dim-1];
+                    if (pAttrs->udas)
+                    {
+                        s = new UserAttributeDeclaration(pAttrs->udas, a);
+                        pAttrs->udas = NULL;
+                    }
+                    break;
+                }
+
+                a = parseBlock(pLastDecl, pAttrs);
+                if (pAttrs->storageClass != STCundefined)
+                {
+                    s = new StorageClassDeclaration(pAttrs->storageClass, a);
+                    pAttrs->storageClass = STCundefined;
+                }
+                if (pAttrs->udas)
+                {
+                    if (s)
+                        a = new Dsymbols(), a->push(s);
+                    s = new UserAttributeDeclaration(pAttrs->udas, a);
+                    pAttrs->udas = NULL;
+                }
+                break;
+
+            case TOKdeprecated:
+            {
+                if (peek(&token)->value != TOKlparen)
+                {
+                    stc = STCdeprecated;
+                    goto Lstc;
+                }
+                nextToken();
+                check(TOKlparen);
+                Expression *e = parseAssignExp();
+                check(TOKrparen);
+                if (pAttrs->depmsg)
+                {
+                    error("conflicting storage class 'deprecated(%s)' and 'deprecated(%s)'",
+                        pAttrs->depmsg->toChars(), e->toChars());
+                }
+                pAttrs->depmsg = e;
+                a = parseBlock(pLastDecl, pAttrs);
+                if (pAttrs->depmsg)
+                {
+                    s = new DeprecatedDeclaration(pAttrs->depmsg, a);
+                    pAttrs->depmsg = NULL;
+                }
+                break;
+            }
+
+            case TOKlbracket:
+            {
+                if (peekNext() == TOKrbracket)
+                    error("empty attribute list is not allowed");
+                error("use @(attributes) instead of [attributes]");
+                Expressions *exps = parseArguments();
+                // no redundant/conflicting check for UDAs
+
+                pAttrs->udas = UserAttributeDeclaration::concat(pAttrs->udas, exps);
+                a = parseBlock(pLastDecl, pAttrs);
+                if (pAttrs->udas)
+                {
+                    s = new UserAttributeDeclaration(pAttrs->udas, a);
+                    pAttrs->udas = NULL;
+                }
+                break;
+            }
+
+            case TOKextern:
+            {
+                if (peek(&token)->value != TOKlparen)
+                {
+                    stc = STCextern;
+                    goto Lstc;
+                }
+
+                Loc linkLoc = token.loc;
+                Identifiers *idents = NULL;
+                CPPMANGLE cppmangle = CPPMANGLEdefault;
+                LINK link = parseLinkage(&idents, &cppmangle);
+                if (pAttrs->link != LINKdefault)
+                {
+                    if (pAttrs->link != link)
+                    {
+                        error("conflicting linkage extern (%s) and extern (%s)",
+                            linkageToChars(pAttrs->link), linkageToChars(link));
+                    }
+                    else if (idents)
+                    {
+                        // Allow:
+                        //      extern(C++, foo) extern(C++, bar) void foo();
+                        // to be equivalent with:
+                        //      extern(C++, foo.bar) void foo();
+                    }
+                    else
+                        error("redundant linkage extern (%s)", linkageToChars(pAttrs->link));
+                }
+                pAttrs->link = link;
+                this->linkage = link;
+                a = parseBlock(pLastDecl, pAttrs);
+                if (idents)
+                {
+                    assert(link == LINKcpp);
+                    assert(idents->dim);
+                    for (size_t i = idents->dim; i;)
+                    {
+                        Identifier *id = (*idents)[--i];
+                        if (s)
+                            a = new Dsymbols(), a->push(s);
+                        s = new Nspace(linkLoc, id, a);
+                    }
+                    delete idents;
+                    pAttrs->link = LINKdefault;
+                }
+                else if (pAttrs->link != LINKdefault)
+                {
+                    s = new LinkDeclaration(pAttrs->link, a);
+                    pAttrs->link = LINKdefault;
+                }
+                else if (cppmangle != CPPMANGLEdefault)
+                {
+                    assert(link == LINKcpp);
+                    s = new CPPMangleDeclaration(cppmangle, a);
+                }
+                break;
+            }
+
+            case TOKprivate:    prot = PROTprivate;     goto Lprot;
+            case TOKpackage:    prot = PROTpackage;     goto Lprot;
+            case TOKprotected:  prot = PROTprotected;   goto Lprot;
+            case TOKpublic:     prot = PROTpublic;      goto Lprot;
+            case TOKexport:     prot = PROTexport;      goto Lprot;
+            Lprot:
+            {
+                if (pAttrs->protection.kind != PROTundefined)
+                {
+                    if (pAttrs->protection.kind != prot)
+                        error("conflicting protection attribute '%s' and '%s'",
+                            protectionToChars(pAttrs->protection.kind), protectionToChars(prot));
+                    else
+                        error("redundant protection attribute '%s'", protectionToChars(prot));
+                }
+                pAttrs->protection.kind = prot;
+
+                nextToken();
+
+                // optional qualified package identifier to bind
+                // protection to
+                Identifiers *pkg_prot_idents = NULL;
+                if (pAttrs->protection.kind == PROTpackage && token.value == TOKlparen)
+                {
+                    pkg_prot_idents = parseQualifiedIdentifier("protection package");
+
+                    if (pkg_prot_idents)
+                        check(TOKrparen);
+                    else
+                    {
+                        while (token.value != TOKsemicolon && token.value != TOKeof)
+                            nextToken();
+                        nextToken();
+                        break;
+                    }
+                }
+
+                Loc attrloc = token.loc;
+                a = parseBlock(pLastDecl, pAttrs);
+                if (pAttrs->protection.kind != PROTundefined)
+                {
+                    if (pAttrs->protection.kind == PROTpackage && pkg_prot_idents)
+                        s = new ProtDeclaration(attrloc, pkg_prot_idents,  a);
+                    else
+                        s = new ProtDeclaration(attrloc, pAttrs->protection, a);
+
+                    pAttrs->protection = Prot(PROTundefined);
+                }
+                break;
+            }
+
+            case TOKalign:
+            {
+                const Loc attrLoc = token.loc;
+
+                nextToken();
+
+                Expression *e = NULL; // default
+                if (token.value == TOKlparen)
+                {
+                    nextToken();
+                    e = parseAssignExp();
+                    check(TOKrparen);
+                }
+
+                if (pAttrs->setAlignment)
+                {
+                    const char *s1 = "";
+                    OutBuffer buf1;
+                    if (e)
+                    {
+                        buf1.printf("(%s)", e->toChars());
+                        s1 = buf1.peekString();
+                    }
+                    error("redundant alignment attribute align%s", s1);
+                }
+
+                pAttrs->setAlignment = true;
+                pAttrs->ealign = e;
+                a = parseBlock(pLastDecl, pAttrs);
+                if (pAttrs->setAlignment)
+                {
+                    s = new AlignDeclaration(attrLoc, pAttrs->ealign, a);
+                    pAttrs->setAlignment = false;
+                    pAttrs->ealign = NULL;
+                }
+                break;
+            }
+
+            case TOKpragma:
+            {
+                Expressions *args = NULL;
+                Loc loc = token.loc;
+
+                nextToken();
+                check(TOKlparen);
+                if (token.value != TOKidentifier)
+                {
+                    error("pragma(identifier) expected");
+                    goto Lerror;
+                }
+                Identifier *ident = token.ident;
+                nextToken();
+                if (token.value == TOKcomma && peekNext() != TOKrparen)
+                    args = parseArguments();    // pragma(identifier, args...)
+                else
+                    check(TOKrparen);           // pragma(identifier)
+
+                Dsymbols *a2 = NULL;
+                if (token.value == TOKsemicolon)
+                {
+                    /* Bugzilla 2354: Accept single semicolon as an empty
+                     * DeclarationBlock following attribute.
+                     *
+                     * Attribute DeclarationBlock
+                     * Pragma    DeclDef
+                     *           ;
+                     */
+                    nextToken();
+                }
+                else
+                    a2 = parseBlock(pLastDecl);
+                s = new PragmaDeclaration(loc, ident, args, a2);
+                break;
+            }
+
+            case TOKdebug:
+                nextToken();
+                if (token.value == TOKassign)
+                {
+                    nextToken();
+                    if (token.value == TOKidentifier)
+                        s = new DebugSymbol(token.loc, token.ident);
+                    else if (token.value == TOKint32v || token.value == TOKint64v)
+                        s = new DebugSymbol(token.loc, (unsigned)token.uns64value);
+                    else
+                    {
+                        error("identifier or integer expected, not %s", token.toChars());
+                        s = NULL;
+                    }
+                    nextToken();
+                    if (token.value != TOKsemicolon)
+                        error("semicolon expected");
+                    nextToken();
+                    break;
+                }
+
+                condition = parseDebugCondition();
+                goto Lcondition;
+
+            case TOKversion:
+                nextToken();
+                if (token.value == TOKassign)
+                {
+                    nextToken();
+                    if (token.value == TOKidentifier)
+                        s = new VersionSymbol(token.loc, token.ident);
+                    else if (token.value == TOKint32v || token.value == TOKint64v)
+                        s = new VersionSymbol(token.loc, (unsigned)token.uns64value);
+                    else
+                    {
+                        error("identifier or integer expected, not %s", token.toChars());
+                        s = NULL;
+                    }
+                    nextToken();
+                    if (token.value != TOKsemicolon)
+                        error("semicolon expected");
+                    nextToken();
+                    break;
+                }
+                condition = parseVersionCondition();
+                goto Lcondition;
+
+            Lcondition:
+            {
+                Dsymbols *athen;
+                if (token.value == TOKcolon)
+                    athen = parseBlock(pLastDecl);
+                else
+                {
+                    Loc lookingForElseSave = lookingForElse;
+                    lookingForElse = token.loc;
+                    athen = parseBlock(pLastDecl);
+                    lookingForElse = lookingForElseSave;
+                }
+                Dsymbols *aelse = NULL;
+                if (token.value == TOKelse)
+                {
+                    Loc elseloc = token.loc;
+                    nextToken();
+                    aelse = parseBlock(pLastDecl);
+                    checkDanglingElse(elseloc);
+                }
+                s = new ConditionalDeclaration(condition, athen, aelse);
+                break;
+            }
+
+            case TOKsemicolon:          // empty declaration
+                //error("empty declaration");
+                nextToken();
+                continue;
+
+            default:
+                error("declaration expected, not '%s'",token.toChars());
+            Lerror:
+                while (token.value != TOKsemicolon && token.value != TOKeof)
+                    nextToken();
+                nextToken();
+                s = NULL;
+                continue;
+        }
+
+        if (s)
+        {
+            if (!s->isAttribDeclaration())
+                *pLastDecl = s;
+            decldefs->push(s);
+            addComment(s, pAttrs->comment);
+        }
+        else if (a && a->dim)
+        {
+            decldefs->append(a);
+        }
+    } while (!once);
+
+    linkage = linksave;
+
+    return decldefs;
+}
+
+/*********************************************
+ * Give error on redundant/conflicting storage class.
+ *
+ * TODO: remove deprecation in 2.068 and keep only error
+ */
+
+StorageClass Parser::appendStorageClass(StorageClass storageClass, StorageClass stc,
+    bool deprec)
+{
+    if ((storageClass & stc) ||
+        (storageClass & STCin && stc & (STCconst | STCscope)) ||
+        (stc & STCin && storageClass & (STCconst | STCscope)))
+    {
+        OutBuffer buf;
+        stcToBuffer(&buf, stc);
+        if (deprec)
+            deprecation("redundant attribute '%s'", buf.peekString());
+        else
+            error("redundant attribute '%s'", buf.peekString());
+        return storageClass | stc;
+    }
+
+    storageClass |= stc;
+
+    if (stc & (STCconst | STCimmutable | STCmanifest))
+    {
+        StorageClass u = storageClass & (STCconst | STCimmutable | STCmanifest);
+        if (u & (u - 1))
+            error("conflicting attribute '%s'", Token::toChars(token.value));
+    }
+    if (stc & (STCgshared | STCshared | STCtls))
+    {
+        StorageClass u = storageClass & (STCgshared | STCshared | STCtls);
+        if (u & (u - 1))
+            error("conflicting attribute '%s'", Token::toChars(token.value));
+    }
+    if (stc & (STCsafe | STCsystem | STCtrusted))
+    {
+        StorageClass u = storageClass & (STCsafe | STCsystem | STCtrusted);
+        if (u & (u - 1))
+            error("conflicting attribute '@%s'", token.toChars());
+    }
+
+    return storageClass;
+}
+
+/***********************************************
+ * Parse attribute, lexer is on '@'.
+ * Input:
+ *      pudas           array of UDAs to append to
+ * Returns:
+ *      storage class   if a predefined attribute; also scanner remains on identifier.
+ *      0               if not a predefined attribute
+ *      *pudas          set if user defined attribute, scanner is past UDA
+ *      *pudas          NULL if not a user defined attribute
+ */
+
+StorageClass Parser::parseAttribute(Expressions **pudas)
+{
+    nextToken();
+    Expressions *udas = NULL;
+    StorageClass stc = 0;
+    if (token.value == TOKidentifier)
+    {
+        if (token.ident == Id::property)
+            stc = STCproperty;
+        else if (token.ident == Id::nogc)
+            stc = STCnogc;
+        else if (token.ident == Id::safe)
+            stc = STCsafe;
+        else if (token.ident == Id::trusted)
+            stc = STCtrusted;
+        else if (token.ident == Id::system)
+            stc = STCsystem;
+        else if (token.ident == Id::disable)
+            stc = STCdisable;
+        else
+        {
+            // Allow identifier, template instantiation, or function call
+            Expression *exp = parsePrimaryExp();
+            if (token.value == TOKlparen)
+            {
+                Loc loc = token.loc;
+                exp = new CallExp(loc, exp, parseArguments());
+            }
+
+            udas = new Expressions();
+            udas->push(exp);
+        }
+    }
+    else if (token.value == TOKlparen)
+    {
+        // @( ArgumentList )
+        // Concatenate with existing
+        if (peekNext() == TOKrparen)
+            error("empty attribute list is not allowed");
+        udas = parseArguments();
+    }
+    else
+    {
+        error("@identifier or @(ArgumentList) expected, not @%s", token.toChars());
+    }
+
+    if (stc)
+    {
+    }
+    else if (udas)
+    {
+        *pudas = UserAttributeDeclaration::concat(*pudas, udas);
+    }
+    else
+        error("valid attributes are @property, @safe, @trusted, @system, @disable");
+    return stc;
+}
+
+/***********************************************
+ * Parse const/immutable/shared/inout/nothrow/pure postfix
+ */
+
+StorageClass Parser::parsePostfix(StorageClass storageClass, Expressions **pudas)
+{
+    while (1)
+    {
+        StorageClass stc;
+        switch (token.value)
+        {
+            case TOKconst:      stc = STCconst;         break;
+            case TOKimmutable:  stc = STCimmutable;     break;
+            case TOKshared:     stc = STCshared;        break;
+            case TOKwild:       stc = STCwild;          break;
+            case TOKnothrow:    stc = STCnothrow;       break;
+            case TOKpure:       stc = STCpure;          break;
+            case TOKreturn:     stc = STCreturn;        break;
+            case TOKscope:      stc = STCscope;         break;
+            case TOKat:
+            {
+                Expressions *udas = NULL;
+                stc = parseAttribute(&udas);
+                if (udas)
+                {
+                    if (pudas)
+                        *pudas = UserAttributeDeclaration::concat(*pudas, udas);
+                    else
+                    {
+                        // Disallow:
+                        //      void function() @uda fp;
+                        //      () @uda { return 1; }
+                        error("user defined attributes cannot appear as postfixes");
+                    }
+                    continue;
+                }
+                break;
+            }
+
+            default:
+                return storageClass;
+        }
+        storageClass = appendStorageClass(storageClass, stc, true);
+        nextToken();
+    }
+}
+
+StorageClass Parser::parseTypeCtor()
+{
+    StorageClass storageClass = STCundefined;
+
+    while (1)
+    {
+        if (peek(&token)->value == TOKlparen)
+            return storageClass;
+
+        StorageClass stc;
+        switch (token.value)
+        {
+            case TOKconst:      stc = STCconst;         break;
+            case TOKimmutable:  stc = STCimmutable;     break;
+            case TOKshared:     stc = STCshared;        break;
+            case TOKwild:       stc = STCwild;          break;
+
+            default:
+                return storageClass;
+        }
+        storageClass = appendStorageClass(storageClass, stc);
+        nextToken();
+    }
+}
+
+/********************************************
+ * Parse declarations after an align, protection, or extern decl.
+ */
+
+Dsymbols *Parser::parseBlock(Dsymbol **pLastDecl, PrefixAttributes *pAttrs)
+{
+    Dsymbols *a = NULL;
+
+    //printf("parseBlock()\n");
+    switch (token.value)
+    {
+        case TOKsemicolon:
+            error("declaration expected following attribute, not ';'");
+            nextToken();
+            break;
+
+        case TOKeof:
+            error("declaration expected following attribute, not EOF");
+            break;
+
+        case TOKlcurly:
+        {
+            Loc lookingForElseSave = lookingForElse;
+            lookingForElse = Loc();
+
+            nextToken();
+            a = parseDeclDefs(0, pLastDecl);
+            if (token.value != TOKrcurly)
+            {
+                /* { */
+                error("matching '}' expected, not %s", token.toChars());
+            }
+            else
+                nextToken();
+            lookingForElse = lookingForElseSave;
+            break;
+        }
+
+        case TOKcolon:
+            nextToken();
+            a = parseDeclDefs(0, pLastDecl);    // grab declarations up to closing curly bracket
+            break;
+
+        default:
+            a = parseDeclDefs(1, pLastDecl, pAttrs);
+            break;
+    }
+    return a;
+}
+
+/**********************************
+ * Parse a static assertion.
+ * Current token is 'static'.
+ */
+
+StaticAssert *Parser::parseStaticAssert()
+{
+    Loc loc = token.loc;
+    Expression *exp;
+    Expression *msg = NULL;
+
+    //printf("parseStaticAssert()\n");
+    nextToken();
+    nextToken();
+    check(TOKlparen);
+    exp = parseAssignExp();
+    if (token.value == TOKcomma)
+    {   nextToken();
+        msg = parseAssignExp();
+    }
+    check(TOKrparen);
+    check(TOKsemicolon);
+    return new StaticAssert(loc, exp, msg);
+}
+
+/***********************************
+ * Parse typeof(expression).
+ * Current token is on the 'typeof'.
+ */
+
+TypeQualified *Parser::parseTypeof()
+{
+    TypeQualified *t;
+    Loc loc = token.loc;
+
+    nextToken();
+    check(TOKlparen);
+    if (token.value == TOKreturn)       // typeof(return)
+    {
+        nextToken();
+        t = new TypeReturn(loc);
+    }
+    else
+    {
+        Expression *exp = parseExpression();    // typeof(expression)
+        t = new TypeTypeof(loc, exp);
+    }
+    check(TOKrparen);
+    return t;
+}
+
+/***********************************
+ * Parse __vector(type).
+ * Current token is on the '__vector'.
+ */
+
+Type *Parser::parseVector()
+{
+    Loc loc = token.loc;
+    nextToken();
+    check(TOKlparen);
+    Type *tb = parseType();
+    check(TOKrparen);
+    return new TypeVector(loc, tb);
+}
+
+/***********************************
+ * Parse:
+ *      extern (linkage)
+ *      extern (C++, namespaces)
+ * The parser is on the 'extern' token.
+ */
+
+LINK Parser::parseLinkage(Identifiers **pidents, CPPMANGLE *pcppmangle)
+{
+    Identifiers *idents = NULL;
+    CPPMANGLE cppmangle = CPPMANGLEdefault;
+    LINK link = LINKdefault;
+    nextToken();
+    assert(token.value == TOKlparen);
+    nextToken();
+    if (token.value == TOKidentifier)
+    {   Identifier *id = token.ident;
+
+        nextToken();
+        if (id == Id::Windows)
+            link = LINKwindows;
+        else if (id == Id::Pascal)
+            link = LINKpascal;
+        else if (id == Id::D)
+            link = LINKd;
+        else if (id == Id::C)
+        {
+            link = LINKc;
+            if (token.value == TOKplusplus)
+            {
+                link = LINKcpp;
+                nextToken();
+                if (token.value == TOKcomma)    // , namespaces or class or struct
+                {
+                    nextToken();
+                    if (token.value == TOKclass || token.value == TOKstruct)
+                    {
+                        cppmangle = token.value == TOKclass ? CPPMANGLEclass : CPPMANGLEstruct;
+                        nextToken();
+                    }
+                    else
+                    {
+                        idents = new Identifiers();
+                        while (1)
+                        {
+                            if (token.value == TOKidentifier)
+                            {
+                                Identifier *idn = token.ident;
+                                idents->push(idn);
+                                nextToken();
+                                if (token.value == TOKdot)
+                                {
+                                    nextToken();
+                                    continue;
+                                }
+                            }
+                            else
+                            {
+                                error("identifier expected for C++ namespace");
+                                idents = NULL;  // error occurred, invalidate list of elements.
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        else if (id == Id::Objective) // Looking for tokens "Objective-C"
+        {
+            if (token.value == TOKmin)
+            {
+                nextToken();
+                if (token.ident == Id::C)
+                {
+                    link = LINKobjc;
+                    nextToken();
+                }
+                else
+                    goto LinvalidLinkage;
+            }
+            else
+                goto LinvalidLinkage;
+        }
+        else if (id == Id::System)
+        {
+            link = LINKsystem;
+        }
+        else
+        {
+        LinvalidLinkage:
+            error("valid linkage identifiers are D, C, C++, Objective-C, Pascal, Windows, System");
+            link = LINKd;
+        }
+    }
+    else
+    {
+        link = LINKd;           // default
+    }
+    check(TOKrparen);
+    *pidents = idents;
+    *pcppmangle = cppmangle;
+    return link;
+}
+
+/***********************************
+ * Parse ident1.ident2.ident3
+ *
+ * Params:
+ *  entity = what qualified identifier is expected to resolve into.
+ *     Used only for better error message
+ *
+ * Returns:
+ *     array of identifiers with actual qualified one stored last
+ */
+Identifiers *Parser::parseQualifiedIdentifier(const char *entity)
+{
+    Identifiers *qualified = NULL;
+
+    do
+    {
+        nextToken();
+        if (token.value != TOKidentifier)
+        {
+            error("%s expected as dot-separated identifiers, got '%s'",
+                    entity, token.toChars());
+            return NULL;
+        }
+
+        Identifier *id = token.ident;
+        if (!qualified)
+            qualified = new Identifiers();
+        qualified->push(id);
+
+        nextToken();
+    } while (token.value == TOKdot);
+
+    return qualified;
+}
+
+/**************************************
+ * Parse a debug conditional
+ */
+
+Condition *Parser::parseDebugCondition()
+{
+    Condition *c;
+
+    if (token.value == TOKlparen)
+    {
+        nextToken();
+        unsigned level = 1;
+        Identifier *id = NULL;
+
+        if (token.value == TOKidentifier)
+            id = token.ident;
+        else if (token.value == TOKint32v || token.value == TOKint64v)
+            level = (unsigned)token.uns64value;
+        else
+            error("identifier or integer expected, not %s", token.toChars());
+        nextToken();
+        check(TOKrparen);
+        c = new DebugCondition(mod, level, id);
+    }
+    else
+        c = new DebugCondition(mod, 1, NULL);
+    return c;
+
+}
+
+/**************************************
+ * Parse a version conditional
+ */
+
+Condition *Parser::parseVersionCondition()
+{
+    Condition *c;
+    unsigned level = 1;
+    Identifier *id = NULL;
+
+    if (token.value == TOKlparen)
+    {
+        nextToken();
+        /* Allow:
+         *    version (unittest)
+         *    version (assert)
+         * even though they are keywords
+         */
+        if (token.value == TOKidentifier)
+            id = token.ident;
+        else if (token.value == TOKint32v || token.value == TOKint64v)
+            level = (unsigned)token.uns64value;
+        else if (token.value == TOKunittest)
+            id = Identifier::idPool(Token::toChars(TOKunittest));
+        else if (token.value == TOKassert)
+            id = Identifier::idPool(Token::toChars(TOKassert));
+        else
+            error("identifier or integer expected, not %s", token.toChars());
+        nextToken();
+        check(TOKrparen);
+
+    }
+    else
+       error("(condition) expected following version");
+    c = new VersionCondition(mod, level, id);
+    return c;
+
+}
+
+/***********************************************
+ *      static if (expression)
+ *          body
+ *      else
+ *          body
+ * Current token is 'static'.
+ */
+
+Condition *Parser::parseStaticIfCondition()
+{
+    Expression *exp;
+    Condition *condition;
+    Loc loc = token.loc;
+
+    nextToken();
+    nextToken();
+    if (token.value == TOKlparen)
+    {
+        nextToken();
+        exp = parseAssignExp();
+        check(TOKrparen);
+    }
+    else
+    {
+        error("(expression) expected following static if");
+        exp = NULL;
+    }
+    condition = new StaticIfCondition(loc, exp);
+    return condition;
+}
+
+
+/*****************************************
+ * Parse a constructor definition:
+ *      this(parameters) { body }
+ * or postblit:
+ *      this(this) { body }
+ * or constructor template:
+ *      this(templateparameters)(parameters) { body }
+ * Current token is 'this'.
+ */
+
+Dsymbol *Parser::parseCtor(PrefixAttributes *pAttrs)
+{
+    Expressions *udas = NULL;
+    Loc loc = token.loc;
+    StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+    nextToken();
+    if (token.value == TOKlparen && peekNext() == TOKthis && peekNext2() == TOKrparen)
+    {
+        // this(this) { ... }
+        nextToken();
+        nextToken();
+        check(TOKrparen);
+
+        stc = parsePostfix(stc, &udas);
+        if (stc & STCstatic)
+            error(loc, "postblit cannot be static");
+
+        PostBlitDeclaration *f = new PostBlitDeclaration(loc, Loc(), stc, Id::postblit);
+        if (pAttrs)
+            pAttrs->storageClass = STCundefined;
+        Dsymbol *s = parseContracts(f);
+        if (udas)
+        {
+            Dsymbols *a = new Dsymbols();
+            a->push(f);
+            s = new UserAttributeDeclaration(udas, a);
+        }
+        return s;
+    }
+
+    /* Look ahead to see if:
+     *   this(...)(...)
+     * which is a constructor template
+     */
+    TemplateParameters *tpl = NULL;
+    if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen)
+    {
+        tpl = parseTemplateParameterList();
+    }
+
+    /* Just a regular constructor
+     */
+    int varargs;
+    Parameters *parameters = parseParameters(&varargs);
+    stc = parsePostfix(stc, &udas);
+    if (varargs != 0 || Parameter::dim(parameters) != 0)
+    {
+        if (stc & STCstatic)
+            error(loc, "constructor cannot be static");
+    }
+    else if (StorageClass ss = stc & (STCshared | STCstatic))   // this()
+    {
+        if (ss == STCstatic)
+            error(loc, "use 'static this()' to declare a static constructor");
+        else if (ss == (STCshared | STCstatic))
+            error(loc, "use 'shared static this()' to declare a shared static constructor");
+    }
+
+    Expression *constraint = tpl ? parseConstraint() : NULL;
+
+    Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc);   // RetrunType -> auto
+    tf = tf->addSTC(stc);
+
+    CtorDeclaration *f = new CtorDeclaration(loc, Loc(), stc, tf);
+    if (pAttrs)
+        pAttrs->storageClass = STCundefined;
+    Dsymbol *s = parseContracts(f);
+    if (udas)
+    {
+        Dsymbols *a = new Dsymbols();
+        a->push(f);
+        s = new UserAttributeDeclaration(udas, a);
+    }
+
+    if (tpl)
+    {
+        // Wrap a template around it
+        Dsymbols *decldefs = new Dsymbols();
+        decldefs->push(s);
+        s = new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs);
+    }
+
+    return s;
+}
+
+/*****************************************
+ * Parse a destructor definition:
+ *      ~this() { body }
+ * Current token is '~'.
+ */
+
+Dsymbol *Parser::parseDtor(PrefixAttributes *pAttrs)
+{
+    Expressions *udas = NULL;
+    Loc loc = token.loc;
+    StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+    nextToken();
+    check(TOKthis);
+    check(TOKlparen);
+    check(TOKrparen);
+
+    stc = parsePostfix(stc, &udas);
+    if (StorageClass ss = stc & (STCshared | STCstatic))
+    {
+        if (ss == STCstatic)
+            error(loc, "use 'static ~this()' to declare a static destructor");
+        else if (ss == (STCshared | STCstatic))
+            error(loc, "use 'shared static ~this()' to declare a shared static destructor");
+    }
+
+    DtorDeclaration *f = new DtorDeclaration(loc, Loc(), stc, Id::dtor);
+    if (pAttrs)
+        pAttrs->storageClass = STCundefined;
+    Dsymbol *s = parseContracts(f);
+    if (udas)
+    {
+        Dsymbols *a = new Dsymbols();
+        a->push(f);
+        s = new UserAttributeDeclaration(udas, a);
+    }
+    return s;
+}
+
+/*****************************************
+ * Parse a static constructor definition:
+ *      static this() { body }
+ * Current token is 'static'.
+ */
+
+Dsymbol *Parser::parseStaticCtor(PrefixAttributes *pAttrs)
+{
+    //Expressions *udas = NULL;
+    Loc loc = token.loc;
+    StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+    nextToken();
+    nextToken();
+    check(TOKlparen);
+    check(TOKrparen);
+
+    stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
+    if (stc & STCshared)
+        error(loc, "use 'shared static this()' to declare a shared static constructor");
+    else if (stc & STCstatic)
+        appendStorageClass(stc, STCstatic);     // complaint for the redundancy
+    else if (StorageClass modStc = stc & STC_TYPECTOR)
+    {
+        OutBuffer buf;
+        stcToBuffer(&buf, modStc);
+        error(loc, "static constructor cannot be %s", buf.peekString());
+    }
+    stc &= ~(STCstatic | STC_TYPECTOR);
+
+    StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, Loc(), stc);
+    if (pAttrs)
+        pAttrs->storageClass = STCundefined;
+    Dsymbol *s = parseContracts(f);
+    return s;
+}
+
+/*****************************************
+ * Parse a static destructor definition:
+ *      static ~this() { body }
+ * Current token is 'static'.
+ */
+
+Dsymbol *Parser::parseStaticDtor(PrefixAttributes *pAttrs)
+{
+    Expressions *udas = NULL;
+    Loc loc = token.loc;
+    StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+    nextToken();
+    nextToken();
+    check(TOKthis);
+    check(TOKlparen);
+    check(TOKrparen);
+
+    stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
+    if (stc & STCshared)
+        error(loc, "use 'shared static ~this()' to declare a shared static destructor");
+    else if (stc & STCstatic)
+        appendStorageClass(stc, STCstatic);     // complaint for the redundancy
+    else if (StorageClass modStc = stc & STC_TYPECTOR)
+    {
+        OutBuffer buf;
+        stcToBuffer(&buf, modStc);
+        error(loc, "static destructor cannot be %s", buf.peekString());
+    }
+    stc &= ~(STCstatic | STC_TYPECTOR);
+
+    StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, Loc(), stc);
+    if (pAttrs)
+        pAttrs->storageClass = STCundefined;
+    Dsymbol *s = parseContracts(f);
+    if (udas)
+    {
+        Dsymbols *a = new Dsymbols();
+        a->push(f);
+        s = new UserAttributeDeclaration(udas, a);
+    }
+    return s;
+}
+
+/*****************************************
+ * Parse a shared static constructor definition:
+ *      shared static this() { body }
+ * Current token is 'shared'.
+ */
+
+Dsymbol *Parser::parseSharedStaticCtor(PrefixAttributes *pAttrs)
+{
+    //Expressions *udas = NULL;
+    Loc loc = token.loc;
+    StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+    nextToken();
+    nextToken();
+    nextToken();
+    check(TOKlparen);
+    check(TOKrparen);
+
+    stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
+    if (StorageClass ss = stc & (STCshared | STCstatic))
+        appendStorageClass(stc, ss);            // complaint for the redundancy
+    else if (StorageClass modStc = stc & STC_TYPECTOR)
+    {
+        OutBuffer buf;
+        stcToBuffer(&buf, modStc);
+        error(loc, "shared static constructor cannot be %s", buf.peekString());
+    }
+    stc &= ~(STCstatic | STC_TYPECTOR);
+
+    SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, Loc(), stc);
+    if (pAttrs)
+        pAttrs->storageClass = STCundefined;
+    Dsymbol *s = parseContracts(f);
+    return s;
+}
+
+/*****************************************
+ * Parse a shared static destructor definition:
+ *      shared static ~this() { body }
+ * Current token is 'shared'.
+ */
+
+Dsymbol *Parser::parseSharedStaticDtor(PrefixAttributes *pAttrs)
+{
+    Expressions *udas = NULL;
+    Loc loc = token.loc;
+    StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+    nextToken();
+    nextToken();
+    nextToken();
+    check(TOKthis);
+    check(TOKlparen);
+    check(TOKrparen);
+
+    stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
+    if (StorageClass ss = stc & (STCshared | STCstatic))
+        appendStorageClass(stc, ss);            // complaint for the redundancy
+    else if (StorageClass modStc = stc & STC_TYPECTOR)
+    {
+        OutBuffer buf;
+        stcToBuffer(&buf, modStc);
+        error(loc, "shared static destructor cannot be %s", buf.peekString());
+    }
+    stc &= ~(STCstatic | STC_TYPECTOR);
+
+    SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, Loc(), stc);
+    if (pAttrs)
+        pAttrs->storageClass = STCundefined;
+    Dsymbol *s = parseContracts(f);
+    if (udas)
+    {
+        Dsymbols *a = new Dsymbols();
+        a->push(f);
+        s = new UserAttributeDeclaration(udas, a);
+    }
+    return s;
+}
+
+/*****************************************
+ * Parse an invariant definition:
+ *      invariant() { body }
+ * Current token is 'invariant'.
+ */
+
+Dsymbol *Parser::parseInvariant(PrefixAttributes *pAttrs)
+{
+    Loc loc = token.loc;
+    StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+    nextToken();
+    if (token.value == TOKlparen)       // optional ()
+    {
+        nextToken();
+        check(TOKrparen);
+    }
+
+    InvariantDeclaration *f = new InvariantDeclaration(loc, Loc(), stc);
+    if (pAttrs)
+        pAttrs->storageClass = STCundefined;
+    f->fbody = parseStatement(PScurly);
+    return f;
+}
+
+/*****************************************
+ * Parse a unittest definition:
+ *      unittest { body }
+ * Current token is 'unittest'.
+ */
+
+Dsymbol *Parser::parseUnitTest(PrefixAttributes *pAttrs)
+{
+    Loc loc = token.loc;
+    StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+    nextToken();
+
+    const utf8_t *begPtr = token.ptr + 1;  // skip '{'
+    const utf8_t *endPtr = NULL;
+    Statement *sbody = parseStatement(PScurly, &endPtr);
+
+    /** Extract unittest body as a string. Must be done eagerly since memory
+    will be released by the lexer before doc gen. */
+    char *docline = NULL;
+    if (global.params.doDocComments && endPtr > begPtr)
+    {
+        /* Remove trailing whitespaces */
+        for (const utf8_t *p = endPtr - 1;
+             begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p)
+        {
+            endPtr = p;
+        }
+
+        size_t len = endPtr - begPtr;
+        if (len > 0)
+        {
+            docline = (char *)mem.xmalloc(len + 2);
+            memcpy(docline, begPtr, len);
+            docline[len  ] = '\n';  // Terminate all lines by LF
+            docline[len+1] = '\0';
+        }
+    }
+
+    UnitTestDeclaration *f = new UnitTestDeclaration(loc, token.loc, stc, docline);
+    if (pAttrs)
+        pAttrs->storageClass = STCundefined;
+    f->fbody = sbody;
+    return f;
+}
+
+/*****************************************
+ * Parse a new definition:
+ *      new(parameters) { body }
+ * Current token is 'new'.
+ */
+
+Dsymbol *Parser::parseNew(PrefixAttributes *pAttrs)
+{
+    Loc loc = token.loc;
+    StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+    nextToken();
+
+    int varargs;
+    Parameters *parameters = parseParameters(&varargs);
+    NewDeclaration *f = new NewDeclaration(loc, Loc(), stc, parameters, varargs);
+    if (pAttrs)
+        pAttrs->storageClass = STCundefined;
+    Dsymbol *s = parseContracts(f);
+    return s;
+}
+
+/*****************************************
+ * Parse a delete definition:
+ *      delete(parameters) { body }
+ * Current token is 'delete'.
+ */
+
+Dsymbol *Parser::parseDelete(PrefixAttributes *pAttrs)
+{
+    Loc loc = token.loc;
+    StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+    nextToken();
+
+    int varargs;
+    Parameters *parameters = parseParameters(&varargs);
+    if (varargs)
+        error("... not allowed in delete function parameter list");
+    DeleteDeclaration *f = new DeleteDeclaration(loc, Loc(), stc, parameters);
+    if (pAttrs)
+        pAttrs->storageClass = STCundefined;
+    Dsymbol *s = parseContracts(f);
+    return s;
+}
+
+/**********************************************
+ * Parse parameter list.
+ */
+
+Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl)
+{
+    Parameters *parameters = new Parameters();
+    int varargs = 0;
+    int hasdefault = 0;
+
+    check(TOKlparen);
+    while (1)
+    {
+        Identifier *ai = NULL;
+        Type *at;
+        StorageClass storageClass = 0;
+        StorageClass stc;
+        Expression *ae;
+
+        for (;1; nextToken())
+        {
+            switch (token.value)
+            {
+                case TOKrparen:
+                    break;
+
+                case TOKdotdotdot:
+                    varargs = 1;
+                    nextToken();
+                    break;
+
+                case TOKconst:
+                    if (peek(&token)->value == TOKlparen)
+                        goto Ldefault;
+                    stc = STCconst;
+                    goto L2;
+
+                case TOKimmutable:
+                    if (peek(&token)->value == TOKlparen)
+                        goto Ldefault;
+                    stc = STCimmutable;
+                    goto L2;
+
+                case TOKshared:
+                    if (peek(&token)->value == TOKlparen)
+                        goto Ldefault;
+                    stc = STCshared;
+                    goto L2;
+
+                case TOKwild:
+                    if (peek(&token)->value == TOKlparen)
+                        goto Ldefault;
+                    stc = STCwild;
+                    goto L2;
+
+                case TOKin:        stc = STCin;         goto L2;
+                case TOKout:       stc = STCout;        goto L2;
+                case TOKref:       stc = STCref;        goto L2;
+                case TOKlazy:      stc = STClazy;       goto L2;
+                case TOKscope:     stc = STCscope;      goto L2;
+                case TOKfinal:     stc = STCfinal;      goto L2;
+                case TOKauto:      stc = STCauto;       goto L2;
+                case TOKreturn:    stc = STCreturn;     goto L2;
+                L2:
+                    storageClass = appendStorageClass(storageClass, stc);
+                    continue;
+
+#if 0
+                case TOKstatic:    stc = STCstatic;             goto L2;
+                case TOKauto:   storageClass = STCauto;         goto L4;
+                case TOKalias:  storageClass = STCalias;        goto L4;
+                L4:
+                    nextToken();
+                    if (token.value == TOKidentifier)
+                    {   ai = token.ident;
+                        nextToken();
+                    }
+                    else
+                        ai = NULL;
+                    at = NULL;          // no type
+                    ae = NULL;          // no default argument
+                    if (token.value == TOKassign)       // = defaultArg
+                    {   nextToken();
+                        ae = parseDefaultInitExp();
+                        hasdefault = 1;
+                    }
+                    else
+                    {   if (hasdefault)
+                            error("default argument expected for alias %s",
+                                    ai ? ai->toChars() : "");
+                    }
+                    goto L3;
+#endif
+
+                default:
+                Ldefault:
+                {   stc = storageClass & (STCin | STCout | STCref | STClazy);
+                    // if stc is not a power of 2
+                    if (stc & (stc - 1) &&
+                        !(stc == (STCin | STCref)))
+                        error("incompatible parameter storage classes");
+                    //if ((storageClass & STCscope) && (storageClass & (STCref | STCout)))
+                        //error("scope cannot be ref or out");
+
+                    Token *t;
+                    if (tpl && token.value == TOKidentifier &&
+                        (t = peek(&token), (t->value == TOKcomma ||
+                                            t->value == TOKrparen ||
+                                            t->value == TOKdotdotdot)))
+                    {
+                        Identifier *id = Identifier::generateId("__T");
+                        Loc loc = token.loc;
+                        at = new TypeIdentifier(loc, id);
+                        if (!*tpl)
+                            *tpl = new TemplateParameters();
+                        TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
+                        (*tpl)->push(tp);
+
+                        ai = token.ident;
+                        nextToken();
+                    }
+                    else
+                        at = parseType(&ai);
+                    ae = NULL;
+                    if (token.value == TOKassign)       // = defaultArg
+                    {   nextToken();
+                        ae = parseDefaultInitExp();
+                        hasdefault = 1;
+                    }
+                    else
+                    {   if (hasdefault)
+                            error("default argument expected for %s",
+                                    ai ? ai->toChars() : at->toChars());
+                    }
+                    if (token.value == TOKdotdotdot)
+                    {   /* This is:
+                         *      at ai ...
+                         */
+
+                        if (storageClass & (STCout | STCref))
+                            error("variadic argument cannot be out or ref");
+                        varargs = 2;
+                        parameters->push(new Parameter(storageClass, at, ai, ae));
+                        nextToken();
+                        break;
+                    }
+                    parameters->push(new Parameter(storageClass, at, ai, ae));
+                    if (token.value == TOKcomma)
+                    {   nextToken();
+                        goto L1;
+                    }
+                    break;
+                }
+            }
+            break;
+        }
+        break;
+
+    L1: ;
+    }
+    check(TOKrparen);
+    *pvarargs = varargs;
+    return parameters;
+}
+
+
+/*************************************
+ */
+
+EnumDeclaration *Parser::parseEnum()
+{
+    EnumDeclaration *e;
+    Identifier *id;
+    Type *memtype;
+    Loc loc = token.loc;
+
+    //printf("Parser::parseEnum()\n");
+    nextToken();
+    if (token.value == TOKidentifier)
+    {
+        id = token.ident;
+        nextToken();
+    }
+    else
+        id = NULL;
+
+    if (token.value == TOKcolon)
+    {
+        nextToken();
+
+        int alt = 0;
+        Loc typeLoc = token.loc;
+        memtype = parseBasicType();
+        memtype = parseDeclarator(memtype, &alt, NULL);
+        checkCstyleTypeSyntax(typeLoc, memtype, alt, NULL);
+    }
+    else
+        memtype = NULL;
+
+    e = new EnumDeclaration(loc, id, memtype);
+    if (token.value == TOKsemicolon && id)
+        nextToken();
+    else if (token.value == TOKlcurly)
+    {
+        //printf("enum definition\n");
+        e->members = new Dsymbols();
+        nextToken();
+        const utf8_t *comment = token.blockComment;
+        while (token.value != TOKrcurly)
+        {
+            /* Can take the following forms:
+             *  1. ident
+             *  2. ident = value
+             *  3. type ident = value
+             */
+
+            loc = token.loc;
+
+            Type *type = NULL;
+            Identifier *ident = NULL;
+            Token *tp = peek(&token);
+            if (token.value == TOKidentifier &&
+                (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly))
+            {
+                ident = token.ident;
+                type = NULL;
+                nextToken();
+            }
+            else
+            {
+                type = parseType(&ident, NULL);
+                if (!ident)
+                    error("no identifier for declarator %s", type->toChars());
+                if (id || memtype)
+                    error("type only allowed if anonymous enum and no enum type");
+            }
+
+            Expression *value;
+            if (token.value == TOKassign)
+            {
+                nextToken();
+                value = parseAssignExp();
+            }
+            else
+            {
+                value = NULL;
+                if (type)
+                    error("if type, there must be an initializer");
+            }
+
+            EnumMember *em = new EnumMember(loc, ident, value, type);
+            e->members->push(em);
+
+            if (token.value == TOKrcurly)
+                ;
+            else
+            {
+                addComment(em, comment);
+                comment = NULL;
+                check(TOKcomma);
+            }
+            addComment(em, comment);
+            comment = token.blockComment;
+
+            if (token.value == TOKeof)
+            {
+                error("premature end of file");
+                break;
+            }
+        }
+        nextToken();
+    }
+    else
+        error("enum declaration is invalid");
+
+    //printf("-parseEnum() %s\n", e->toChars());
+    return e;
+}
+
+/********************************
+ * Parse struct, union, interface, class.
+ */
+
+Dsymbol *Parser::parseAggregate()
+{
+    AggregateDeclaration *a = NULL;
+    int anon = 0;
+    Identifier *id;
+    TemplateParameters *tpl = NULL;
+    Expression *constraint = NULL;
+    Loc loc = token.loc;
+    TOK tok = token.value;
+
+    //printf("Parser::parseAggregate()\n");
+    nextToken();
+    if (token.value != TOKidentifier)
+    {
+        id = NULL;
+    }
+    else
+    {
+        id = token.ident;
+        nextToken();
+
+        if (token.value == TOKlparen)
+        {
+            // Class template declaration.
+            // Gather template parameter list
+            tpl = parseTemplateParameterList();
+            constraint = parseConstraint();
+        }
+    }
+
+    switch (tok)
+    {
+        case TOKclass:
+        case TOKinterface:
+        {
+            if (!id)
+                error(loc, "anonymous classes not allowed");
+
+            // Collect base class(es)
+            BaseClasses *baseclasses = NULL;
+            if (token.value == TOKcolon)
+            {
+                nextToken();
+                baseclasses = parseBaseClasses();
+
+                if (tpl)
+                {
+                    Expression *tempCons = parseConstraint();
+                    if (tempCons)
+                    {
+                        if (constraint)
+                            error("members expected");
+                        else
+                            constraint = tempCons;
+                    }
+                }
+
+                if (token.value != TOKlcurly)
+                    error("members expected");
+            }
+
+            if (tok == TOKclass)
+            {
+                bool inObject = md && !md->packages && md->id == Id::object;
+                a = new ClassDeclaration(loc, id, baseclasses, NULL, inObject);
+            }
+            else
+                a = new InterfaceDeclaration(loc, id, baseclasses);
+            break;
+        }
+
+        case TOKstruct:
+            if (id)
+            {
+                bool inObject = md && !md->packages && md->id == Id::object;
+                a = new StructDeclaration(loc, id, inObject);
+            }
+            else
+                anon = 1;
+            break;
+
+        case TOKunion:
+            if (id)
+                a = new UnionDeclaration(loc, id);
+            else
+                anon = 2;
+            break;
+
+        default:
+            assert(0);
+            break;
+    }
+    if (a && token.value == TOKsemicolon)
+    {
+        nextToken();
+    }
+    else if (token.value == TOKlcurly)
+    {
+        //printf("aggregate definition\n");
+        nextToken();
+        Dsymbols *decl = parseDeclDefs(0);
+        if (token.value != TOKrcurly)
+            error("} expected following members in %s declaration at %s",
+                Token::toChars(tok), loc.toChars());
+        nextToken();
+        if (anon)
+        {
+            /* Anonymous structs/unions are more like attributes.
+             */
+            return new AnonDeclaration(loc, anon == 2, decl);
+        }
+        else
+            a->members = decl;
+    }
+    else
+    {
+        error("{ } expected following %s declaration", Token::toChars(tok));
+        a = new StructDeclaration(loc, NULL, false);
+    }
+
+    if (tpl)
+    {
+        // Wrap a template around the aggregate declaration
+        Dsymbols *decldefs = new Dsymbols();
+        decldefs->push(a);
+        TemplateDeclaration *tempdecl =
+                new TemplateDeclaration(loc, id, tpl, constraint, decldefs);
+        return tempdecl;
+    }
+
+    return a;
+}
+
+/*******************************************
+ */
+
+BaseClasses *Parser::parseBaseClasses()
+{
+    BaseClasses *baseclasses = new BaseClasses();
+
+    for (; 1; nextToken())
+    {
+        bool prot = false;
+        Prot protection = Prot(PROTpublic);
+        switch (token.value)
+        {
+            case TOKprivate:
+                prot = true;
+                protection = Prot(PROTprivate);
+                nextToken();
+                break;
+            case TOKpackage:
+                prot = true;
+                protection = Prot(PROTpackage);
+                nextToken();
+                break;
+            case TOKprotected:
+                prot = true;
+                protection = Prot(PROTprotected);
+                nextToken();
+                break;
+            case TOKpublic:
+                prot = true;
+                protection = Prot(PROTpublic);
+                nextToken();
+                break;
+            default: break;
+        }
+        if (prot)
+            error("use of base class protection is no longer supported");
+        BaseClass *b = new BaseClass(parseBasicType());
+        baseclasses->push(b);
+        if (token.value != TOKcomma)
+            break;
+    }
+    return baseclasses;
+}
+
+/**************************************
+ * Parse constraint.
+ * Constraint is of the form:
+ *      if ( ConstraintExpression )
+ */
+
+Expression *Parser::parseConstraint()
+{   Expression *e = NULL;
+
+    if (token.value == TOKif)
+    {
+        nextToken();    // skip over 'if'
+        check(TOKlparen);
+        e = parseExpression();
+        check(TOKrparen);
+    }
+    return e;
+}
+
+/**************************************
+ * Parse a TemplateDeclaration.
+ */
+
+TemplateDeclaration *Parser::parseTemplateDeclaration(bool ismixin)
+{
+    TemplateDeclaration *tempdecl;
+    Identifier *id;
+    TemplateParameters *tpl;
+    Dsymbols *decldefs;
+    Expression *constraint = NULL;
+    Loc loc = token.loc;
+
+    nextToken();
+    if (token.value != TOKidentifier)
+    {
+        error("identifier expected following template");
+        goto Lerr;
+    }
+    id = token.ident;
+    nextToken();
+    tpl = parseTemplateParameterList();
+    if (!tpl)
+        goto Lerr;
+
+    constraint = parseConstraint();
+
+    if (token.value != TOKlcurly)
+    {
+        error("members of template declaration expected");
+        goto Lerr;
+    }
+    else
+    {
+        nextToken();
+        decldefs = parseDeclDefs(0);
+        if (token.value != TOKrcurly)
+        {
+            error("template member expected");
+            goto Lerr;
+        }
+        nextToken();
+    }
+
+    tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
+    return tempdecl;
+
+Lerr:
+    return NULL;
+}
+
+/******************************************
+ * Parse template parameter list.
+ * Input:
+ *      flag    0: parsing "( list )"
+ *              1: parsing non-empty "list )"
+ */
+
+TemplateParameters *Parser::parseTemplateParameterList(int flag)
+{
+    TemplateParameters *tpl = new TemplateParameters();
+
+    if (!flag && token.value != TOKlparen)
+    {   error("parenthesized TemplateParameterList expected following TemplateIdentifier");
+        goto Lerr;
+    }
+    nextToken();
+
+    // Get array of TemplateParameters
+    if (flag || token.value != TOKrparen)
+    {
+        int isvariadic = 0;
+        while (token.value != TOKrparen)
+        {
+            TemplateParameter *tp;
+            Loc loc;
+            Identifier *tp_ident = NULL;
+            Type *tp_spectype = NULL;
+            Type *tp_valtype = NULL;
+            Type *tp_defaulttype = NULL;
+            Expression *tp_specvalue = NULL;
+            Expression *tp_defaultvalue = NULL;
+            Token *t;
+
+            // Get TemplateParameter
+
+            // First, look ahead to see if it is a TypeParameter or a ValueParameter
+            t = peek(&token);
+            if (token.value == TOKalias)
+            {   // AliasParameter
+                nextToken();
+                loc = token.loc;    // todo
+                Type *spectype = NULL;
+                if (isDeclaration(&token, 2, TOKreserved, NULL))
+                {
+                    spectype = parseType(&tp_ident);
+                }
+                else
+                {
+                    if (token.value != TOKidentifier)
+                    {
+                        error("identifier expected for template alias parameter");
+                        goto Lerr;
+                    }
+                    tp_ident = token.ident;
+                    nextToken();
+                }
+                RootObject *spec = NULL;
+                if (token.value == TOKcolon)    // : Type
+                {
+                    nextToken();
+                    if (isDeclaration(&token, 0, TOKreserved, NULL))
+                        spec = parseType();
+                    else
+                        spec = parseCondExp();
+                }
+                RootObject *def = NULL;
+                if (token.value == TOKassign)   // = Type
+                {
+                    nextToken();
+                    if (isDeclaration(&token, 0, TOKreserved, NULL))
+                        def = parseType();
+                    else
+                        def = parseCondExp();
+                }
+                tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
+            }
+            else if (t->value == TOKcolon || t->value == TOKassign ||
+                     t->value == TOKcomma || t->value == TOKrparen)
+            {
+                // TypeParameter
+                if (token.value != TOKidentifier)
+                {
+                    error("identifier expected for template type parameter");
+                    goto Lerr;
+                }
+                loc = token.loc;
+                tp_ident = token.ident;
+                nextToken();
+                if (token.value == TOKcolon)    // : Type
+                {
+                    nextToken();
+                    tp_spectype = parseType();
+                }
+                if (token.value == TOKassign)   // = Type
+                {
+                    nextToken();
+                    tp_defaulttype = parseType();
+                }
+                tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+            }
+            else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
+            {
+                // ident...
+                if (isvariadic)
+                    error("variadic template parameter must be last");
+                isvariadic = 1;
+                loc = token.loc;
+                tp_ident = token.ident;
+                nextToken();
+                nextToken();
+                tp = new TemplateTupleParameter(loc, tp_ident);
+            }
+            else if (token.value == TOKthis)
+            {
+                // ThisParameter
+                nextToken();
+                if (token.value != TOKidentifier)
+                {
+                    error("identifier expected for template this parameter");
+                    goto Lerr;
+                }
+                loc = token.loc;
+                tp_ident = token.ident;
+                nextToken();
+                if (token.value == TOKcolon)    // : Type
+                {
+                    nextToken();
+                    tp_spectype = parseType();
+                }
+                if (token.value == TOKassign)   // = Type
+                {
+                    nextToken();
+                    tp_defaulttype = parseType();
+                }
+                tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+            }
+            else
+            {
+                // ValueParameter
+                loc = token.loc;    // todo
+                tp_valtype = parseType(&tp_ident);
+                if (!tp_ident)
+                {
+                    error("identifier expected for template value parameter");
+                    tp_ident = Identifier::idPool("error");
+                }
+                if (token.value == TOKcolon)    // : CondExpression
+                {
+                    nextToken();
+                    tp_specvalue = parseCondExp();
+                }
+                if (token.value == TOKassign)   // = CondExpression
+                {
+                    nextToken();
+                    tp_defaultvalue = parseDefaultInitExp();
+                }
+                tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
+            }
+            tpl->push(tp);
+            if (token.value != TOKcomma)
+                break;
+            nextToken();
+        }
+    }
+    check(TOKrparen);
+Lerr:
+    return tpl;
+}
+
+/******************************************
+ * Parse template mixin.
+ *      mixin Foo;
+ *      mixin Foo!(args);
+ *      mixin a.b.c!(args).Foo!(args);
+ *      mixin Foo!(args) identifier;
+ *      mixin typeof(expr).identifier!(args);
+ */
+
+Dsymbol *Parser::parseMixin()
+{
+    TemplateMixin *tm;
+    Identifier *id;
+    Objects *tiargs;
+
+    //printf("parseMixin()\n");
+    Loc locMixin = token.loc;
+    nextToken();    // skip 'mixin'
+
+    Loc loc = token.loc;
+    TypeQualified *tqual = NULL;
+    if (token.value == TOKdot)
+    {
+        id = Id::empty;
+    }
+    else
+    {
+        if (token.value == TOKtypeof)
+        {
+            tqual = parseTypeof();
+            check(TOKdot);
+        }
+        if (token.value != TOKidentifier)
+        {
+            error("identifier expected, not %s", token.toChars());
+            id = Id::empty;
+        }
+        else
+            id = token.ident;
+        nextToken();
+    }
+
+    while (1)
+    {
+        tiargs = NULL;
+        if (token.value == TOKnot)
+        {
+            tiargs = parseTemplateArguments();
+        }
+
+        if (tiargs && token.value == TOKdot)
+        {
+            TemplateInstance *tempinst = new TemplateInstance(loc, id);
+            tempinst->tiargs = tiargs;
+            if (!tqual)
+                tqual = new TypeInstance(loc, tempinst);
+            else
+                tqual->addInst(tempinst);
+            tiargs = NULL;
+        }
+        else
+        {
+            if (!tqual)
+                tqual = new TypeIdentifier(loc, id);
+            else
+                tqual->addIdent(id);
+        }
+
+        if (token.value != TOKdot)
+            break;
+
+        nextToken();
+        if (token.value != TOKidentifier)
+        {
+            error("identifier expected following '.' instead of '%s'", token.toChars());
+            break;
+        }
+        loc = token.loc;
+        id = token.ident;
+        nextToken();
+    }
+
+    if (token.value == TOKidentifier)
+    {
+        id = token.ident;
+        nextToken();
+    }
+    else
+        id = NULL;
+
+    tm = new TemplateMixin(locMixin, id, tqual, tiargs);
+    if (token.value != TOKsemicolon)
+        error("';' expected after mixin");
+    nextToken();
+
+    return tm;
+}
+
+/******************************************
+ * Parse template arguments.
+ * Input:
+ *      current token is opening '!'
+ * Output:
+ *      current token is one after closing ')'
+ */
+
+Objects *Parser::parseTemplateArguments()
+{
+    Objects *tiargs;
+
+    nextToken();
+    if (token.value == TOKlparen)
+    {
+        // ident!(template_arguments)
+        tiargs = parseTemplateArgumentList();
+    }
+    else
+    {
+        // ident!template_argument
+        tiargs = parseTemplateSingleArgument();
+    }
+    if (token.value == TOKnot)
+    {
+        TOK tok = peekNext();
+        if (tok != TOKis && tok != TOKin)
+        {
+            error("multiple ! arguments are not allowed");
+        Lagain:
+            nextToken();
+            if (token.value == TOKlparen)
+                parseTemplateArgumentList();
+            else
+                parseTemplateSingleArgument();
+            if (token.value == TOKnot && (tok = peekNext()) != TOKis && tok != TOKin)
+                goto Lagain;
+        }
+    }
+    return tiargs;
+}
+
+/******************************************
+ * Parse template argument list.
+ * Input:
+ *      current token is opening '(',
+ *          or ',' for __traits
+ * Output:
+ *      current token is one after closing ')'
+ */
+
+Objects *Parser::parseTemplateArgumentList()
+{
+    //printf("Parser::parseTemplateArgumentList()\n");
+    Objects *tiargs = new Objects();
+    TOK endtok = TOKrparen;
+    assert(token.value == TOKlparen || token.value == TOKcomma);
+    nextToken();
+
+    // Get TemplateArgumentList
+    while (token.value != endtok)
+    {
+            // See if it is an Expression or a Type
+            if (isDeclaration(&token, 0, TOKreserved, NULL))
+            {   // Template argument is a type
+                Type *ta = parseType();
+                tiargs->push(ta);
+            }
+            else
+            {   // Template argument is an expression
+                Expression *ea = parseAssignExp();
+                tiargs->push(ea);
+            }
+            if (token.value != TOKcomma)
+                break;
+            nextToken();
+    }
+    check(endtok, "template argument list");
+    return tiargs;
+}
+
+/*****************************
+ * Parse single template argument, to support the syntax:
+ *      foo!arg
+ * Input:
+ *      current token is the arg
+ */
+
+Objects *Parser::parseTemplateSingleArgument()
+{
+    //printf("parseTemplateSingleArgument()\n");
+    Objects *tiargs = new Objects();
+    Type *ta;
+    switch (token.value)
+    {
+        case TOKidentifier:
+            ta = new TypeIdentifier(token.loc, token.ident);
+            goto LabelX;
+
+        case TOKvector:
+            ta = parseVector();
+            goto LabelX;
+
+        case TOKvoid:    ta = Type::tvoid;  goto LabelX;
+        case TOKint8:    ta = Type::tint8;  goto LabelX;
+        case TOKuns8:    ta = Type::tuns8;  goto LabelX;
+        case TOKint16:   ta = Type::tint16; goto LabelX;
+        case TOKuns16:   ta = Type::tuns16; goto LabelX;
+        case TOKint32:   ta = Type::tint32; goto LabelX;
+        case TOKuns32:   ta = Type::tuns32; goto LabelX;
+        case TOKint64:   ta = Type::tint64; goto LabelX;
+        case TOKuns64:   ta = Type::tuns64; goto LabelX;
+        case TOKint128:  ta = Type::tint128; goto LabelX;
+        case TOKuns128:  ta = Type::tuns128; goto LabelX;
+        case TOKfloat32: ta = Type::tfloat32; goto LabelX;
+        case TOKfloat64: ta = Type::tfloat64; goto LabelX;
+        case TOKfloat80: ta = Type::tfloat80; goto LabelX;
+        case TOKimaginary32: ta = Type::timaginary32; goto LabelX;
+        case TOKimaginary64: ta = Type::timaginary64; goto LabelX;
+        case TOKimaginary80: ta = Type::timaginary80; goto LabelX;
+        case TOKcomplex32: ta = Type::tcomplex32; goto LabelX;
+        case TOKcomplex64: ta = Type::tcomplex64; goto LabelX;
+        case TOKcomplex80: ta = Type::tcomplex80; goto LabelX;
+        case TOKbool:    ta = Type::tbool;    goto LabelX;
+        case TOKchar:    ta = Type::tchar;    goto LabelX;
+        case TOKwchar:   ta = Type::twchar; goto LabelX;
+        case TOKdchar:   ta = Type::tdchar; goto LabelX;
+        LabelX:
+            tiargs->push(ta);
+            nextToken();
+            break;
+
+        case TOKint32v:
+        case TOKuns32v:
+        case TOKint64v:
+        case TOKuns64v:
+        case TOKint128v:
+        case TOKuns128v:
+        case TOKfloat32v:
+        case TOKfloat64v:
+        case TOKfloat80v:
+        case TOKimaginary32v:
+        case TOKimaginary64v:
+        case TOKimaginary80v:
+        case TOKnull:
+        case TOKtrue:
+        case TOKfalse:
+        case TOKcharv:
+        case TOKwcharv:
+        case TOKdcharv:
+        case TOKstring:
+        case TOKxstring:
+        case TOKfile:
+        case TOKfilefullpath:
+        case TOKline:
+        case TOKmodulestring:
+        case TOKfuncstring:
+        case TOKprettyfunc:
+        case TOKthis:
+        {   // Template argument is an expression
+            Expression *ea = parsePrimaryExp();
+            tiargs->push(ea);
+            break;
+        }
+
+        default:
+            error("template argument expected following !");
+            break;
+    }
+    return tiargs;
+}
+
+Dsymbols *Parser::parseImport()
+{
+    Dsymbols *decldefs = new Dsymbols();
+    Identifier *aliasid = NULL;
+
+    int isstatic = token.value == TOKstatic;
+    if (isstatic)
+        nextToken();
+
+    //printf("Parser::parseImport()\n");
+    do
+    {
+     L1:
+        nextToken();
+        if (token.value != TOKidentifier)
+        {
+            error("identifier expected following import");
+            break;
+        }
+
+        Loc loc = token.loc;
+        Identifier *id = token.ident;
+        Identifiers *a = NULL;
+        nextToken();
+        if (!aliasid && token.value == TOKassign)
+        {
+            aliasid = id;
+            goto L1;
+        }
+        while (token.value == TOKdot)
+        {
+            if (!a)
+                a = new Identifiers();
+            a->push(id);
+            nextToken();
+            if (token.value != TOKidentifier)
+            {
+                error("identifier expected following package");
+                break;
+            }
+            id = token.ident;
+            nextToken();
+        }
+
+        Import *s = new Import(loc, a, id, aliasid, isstatic);
+        decldefs->push(s);
+
+        /* Look for
+         *      : alias=name, alias=name;
+         * syntax.
+         */
+        if (token.value == TOKcolon)
+        {
+            do
+            {
+                nextToken();
+                if (token.value != TOKidentifier)
+                {
+                    error("identifier expected following :");
+                    break;
+                }
+                Identifier *alias = token.ident;
+                Identifier *name;
+                nextToken();
+                if (token.value == TOKassign)
+                {
+                    nextToken();
+                    if (token.value != TOKidentifier)
+                    {
+                        error("identifier expected following %s=", alias->toChars());
+                        break;
+                    }
+                    name = token.ident;
+                    nextToken();
+                }
+                else
+                {
+                    name = alias;
+                    alias = NULL;
+                }
+                s->addAlias(name, alias);
+            } while (token.value == TOKcomma);
+            break;      // no comma-separated imports of this form
+        }
+
+        aliasid = NULL;
+    } while (token.value == TOKcomma);
+
+    if (token.value == TOKsemicolon)
+        nextToken();
+    else
+    {
+        error("';' expected");
+        nextToken();
+    }
+
+    return decldefs;
+}
+
+Type *Parser::parseType(Identifier **pident, TemplateParameters **ptpl)
+{
+    /* Take care of the storage class prefixes that
+     * serve as type attributes:
+     *               const type
+     *           immutable type
+     *              shared type
+     *               inout type
+     *         inout const type
+     *        shared const type
+     *        shared inout type
+     *  shared inout const type
+     */
+    StorageClass stc = 0;
+    while (1)
+    {
+        switch (token.value)
+        {
+            case TOKconst:
+                if (peekNext() == TOKlparen)
+                    break;              // const as type constructor
+                stc |= STCconst;        // const as storage class
+                nextToken();
+                continue;
+
+            case TOKimmutable:
+                if (peekNext() == TOKlparen)
+                    break;
+                stc |= STCimmutable;
+                nextToken();
+                continue;
+
+            case TOKshared:
+                if (peekNext() == TOKlparen)
+                    break;
+                stc |= STCshared;
+                nextToken();
+                continue;
+
+            case TOKwild:
+                if (peekNext() == TOKlparen)
+                    break;
+                stc |= STCwild;
+                nextToken();
+                continue;
+
+            default:
+                break;
+        }
+        break;
+    }
+
+    Loc typeLoc = token.loc;
+
+    Type *t;
+    t = parseBasicType();
+
+    int alt = 0;
+    t = parseDeclarator(t, &alt, pident, ptpl);
+    checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : NULL);
+
+    t = t->addSTC(stc);
+    return t;
+}
+
+Type *Parser::parseBasicType(bool dontLookDotIdents)
+{
+    Type *t;
+    Loc loc;
+    Identifier *id;
+
+    //printf("parseBasicType()\n");
+    switch (token.value)
+    {
+        case TOKvoid:    t = Type::tvoid;  goto LabelX;
+        case TOKint8:    t = Type::tint8;  goto LabelX;
+        case TOKuns8:    t = Type::tuns8;  goto LabelX;
+        case TOKint16:   t = Type::tint16; goto LabelX;
+        case TOKuns16:   t = Type::tuns16; goto LabelX;
+        case TOKint32:   t = Type::tint32; goto LabelX;
+        case TOKuns32:   t = Type::tuns32; goto LabelX;
+        case TOKint64:   t = Type::tint64; goto LabelX;
+        case TOKuns64:   t = Type::tuns64; goto LabelX;
+        case TOKint128:  t = Type::tint128; goto LabelX;
+        case TOKuns128:  t = Type::tuns128; goto LabelX;
+        case TOKfloat32: t = Type::tfloat32; goto LabelX;
+        case TOKfloat64: t = Type::tfloat64; goto LabelX;
+        case TOKfloat80: t = Type::tfloat80; goto LabelX;
+        case TOKimaginary32: t = Type::timaginary32; goto LabelX;
+        case TOKimaginary64: t = Type::timaginary64; goto LabelX;
+        case TOKimaginary80: t = Type::timaginary80; goto LabelX;
+        case TOKcomplex32: t = Type::tcomplex32; goto LabelX;
+        case TOKcomplex64: t = Type::tcomplex64; goto LabelX;
+        case TOKcomplex80: t = Type::tcomplex80; goto LabelX;
+        case TOKbool:    t = Type::tbool;    goto LabelX;
+        case TOKchar:    t = Type::tchar;    goto LabelX;
+        case TOKwchar:   t = Type::twchar; goto LabelX;
+        case TOKdchar:   t = Type::tdchar; goto LabelX;
+        LabelX:
+            nextToken();
+            break;
+
+        case TOKthis:
+        case TOKsuper:
+        case TOKidentifier:
+            loc = token.loc;
+            id = token.ident;
+            nextToken();
+            if (token.value == TOKnot)
+            {
+                // ident!(template_arguments)
+                TemplateInstance *tempinst = new TemplateInstance(loc, id);
+                tempinst->tiargs = parseTemplateArguments();
+                t = parseBasicTypeStartingAt(new TypeInstance(loc, tempinst), dontLookDotIdents);
+            }
+            else
+            {
+                t = parseBasicTypeStartingAt(new TypeIdentifier(loc, id), dontLookDotIdents);
+            }
+            break;
+
+        case TOKdot:
+            // Leading . as in .foo
+            t = parseBasicTypeStartingAt(new TypeIdentifier(token.loc, Id::empty), dontLookDotIdents);
+            break;
+
+        case TOKtypeof:
+            // typeof(expression)
+            t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents);
+            break;
+
+        case TOKvector:
+            t = parseVector();
+            break;
+
+        case TOKconst:
+            // const(type)
+            nextToken();
+            check(TOKlparen);
+            t = parseType()->addSTC(STCconst);
+            check(TOKrparen);
+            break;
+
+        case TOKimmutable:
+            // immutable(type)
+            nextToken();
+            check(TOKlparen);
+            t = parseType()->addSTC(STCimmutable);
+            check(TOKrparen);
+            break;
+
+        case TOKshared:
+            // shared(type)
+            nextToken();
+            check(TOKlparen);
+            t = parseType()->addSTC(STCshared);
+            check(TOKrparen);
+            break;
+
+        case TOKwild:
+            // wild(type)
+            nextToken();
+            check(TOKlparen);
+            t = parseType()->addSTC(STCwild);
+            check(TOKrparen);
+            break;
+
+        default:
+            error("basic type expected, not %s", token.toChars());
+            t = Type::terror;
+            break;
+    }
+    return t;
+}
+
+Type *Parser::parseBasicTypeStartingAt(TypeQualified *tid, bool dontLookDotIdents)
+{
+    Type *maybeArray = NULL;
+    // See https://issues.dlang.org/show_bug.cgi?id=1215
+    // A basic type can look like MyType (typical case), but also:
+    //  MyType.T -> A type
+    //  MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
+    //  MyType[expr].T -> A type.
+    //  MyType[expr].T[expr] ->  Either a static array of MyType[expr].T or a type
+    //                           (iif MyType[expr].T is a Ttuple)
+    while (1)
+    {
+        switch (token.value)
+        {
+            case TOKdot:
+            {
+                nextToken();
+                if (token.value != TOKidentifier)
+                {
+                    error("identifier expected following '.' instead of '%s'", token.toChars());
+                    break;
+                }
+                if (maybeArray)
+                {
+                    // This is actually a TypeTuple index, not an {a/s}array.
+                    // We need to have a while loop to unwind all index taking:
+                    // T[e1][e2].U   ->  T, addIndex(e1), addIndex(e2)
+                    Objects dimStack;
+                    Type *t = maybeArray;
+                    while (true)
+                    {
+                        if (t->ty == Tsarray)
+                        {
+                            // The index expression is an Expression.
+                            TypeSArray *a = (TypeSArray *)t;
+                            dimStack.push(a->dim->syntaxCopy());
+                            t = a->next->syntaxCopy();
+                        }
+                        else if (t->ty == Taarray)
+                        {
+                            // The index expression is a Type. It will be interpreted as an expression at semantic time.
+                            TypeAArray *a = (TypeAArray *)t;
+                            dimStack.push(a->index->syntaxCopy());
+                            t = a->next->syntaxCopy();
+                        }
+                        else
+                        {
+                            break;
+                        }
+                    }
+                    assert(dimStack.dim > 0);
+                    // We're good. Replay indices in the reverse order.
+                    tid = (TypeQualified *)t;
+                    while (dimStack.dim)
+                    {
+                        tid->addIndex(dimStack.pop());
+                    }
+                    maybeArray = NULL;
+                }
+                Loc loc = token.loc;
+                Identifier *id = token.ident;
+                nextToken();
+                if (token.value == TOKnot)
+                {
+                    TemplateInstance *tempinst = new TemplateInstance(loc, id);
+                    tempinst->tiargs = parseTemplateArguments();
+                    tid->addInst(tempinst);
+                }
+                else
+                    tid->addIdent(id);
+                continue;
+            }
+            case TOKlbracket:
+            {
+                if (dontLookDotIdents)      // workaround for Bugzilla 14911
+                    goto Lend;
+
+                nextToken();
+                Type *t = maybeArray ? maybeArray : (Type *)tid;
+                if (token.value == TOKrbracket)
+                {
+                    // It's a dynamic array, and we're done:
+                    // T[].U does not make sense.
+                    t = new TypeDArray(t);
+                    nextToken();
+                    return t;
+                }
+                else if (isDeclaration(&token, 0, TOKrbracket, NULL))
+                {
+                    // This can be one of two things:
+                    //  1 - an associative array declaration, T[type]
+                    //  2 - an associative array declaration, T[expr]
+                    // These  can only be disambiguated later.
+                    Type *index = parseType();          // [ type ]
+                    maybeArray = new TypeAArray(t, index);
+                    check(TOKrbracket);
+                }
+                else
+                {
+                    // This can be one of three things:
+                    //  1 - an static array declaration, T[expr]
+                    //  2 - a slice, T[expr .. expr]
+                    //  3 - a template parameter pack index expression, T[expr].U
+                    // 1 and 3 can only be disambiguated later.
+                    //printf("it's type[expression]\n");
+                    inBrackets++;
+                    Expression *e = parseAssignExp();           // [ expression ]
+                    if (token.value == TOKslice)
+                    {
+                        // It's a slice, and we're done.
+                        nextToken();
+                        Expression *e2 = parseAssignExp();      // [ exp .. exp ]
+                        t = new TypeSlice(t, e, e2);
+                        inBrackets--;
+                        check(TOKrbracket);
+                        return t;
+                    }
+                    else
+                    {
+                        maybeArray = new TypeSArray(t, e);
+                        inBrackets--;
+                        check(TOKrbracket);
+                        continue;
+                    }
+                }
+                break;
+            }
+            default:
+                goto Lend;
+        }
+    }
+Lend:
+    return maybeArray ? maybeArray : (Type *)tid;
+}
+
+/******************************************
+ * Parse things that follow the initial type t.
+ *      t *
+ *      t []
+ *      t [type]
+ *      t [expression]
+ *      t [expression .. expression]
+ *      t function
+ *      t delegate
+ */
+
+Type *Parser::parseBasicType2(Type *t)
+{
+    //printf("parseBasicType2()\n");
+    while (1)
+    {
+        switch (token.value)
+        {
+            case TOKmul:
+                t = new TypePointer(t);
+                nextToken();
+                continue;
+
+            case TOKlbracket:
+                // Handle []. Make sure things like
+                //     int[3][1] a;
+                // is (array[1] of array[3] of int)
+                nextToken();
+                if (token.value == TOKrbracket)
+                {
+                    t = new TypeDArray(t);                      // []
+                    nextToken();
+                }
+                else if (isDeclaration(&token, 0, TOKrbracket, NULL))
+                {
+                    // It's an associative array declaration
+                    //printf("it's an associative array\n");
+                    Type *index = parseType();          // [ type ]
+                    t = new TypeAArray(t, index);
+                    check(TOKrbracket);
+                }
+                else
+                {
+                    //printf("it's type[expression]\n");
+                    inBrackets++;
+                    Expression *e = parseAssignExp();           // [ expression ]
+                    if (token.value == TOKslice)
+                    {
+                        nextToken();
+                        Expression *e2 = parseAssignExp();      // [ exp .. exp ]
+                        t = new TypeSlice(t, e, e2);
+                    }
+                    else
+                    {
+                        t = new TypeSArray(t,e);
+                    }
+                    inBrackets--;
+                    check(TOKrbracket);
+                }
+                continue;
+
+            case TOKdelegate:
+            case TOKfunction:
+            {
+                // Handle delegate declaration:
+                //      t delegate(parameter list) nothrow pure
+                //      t function(parameter list) nothrow pure
+                TOK save = token.value;
+                nextToken();
+
+                int varargs;
+                Parameters *parameters = parseParameters(&varargs);
+
+                StorageClass stc = parsePostfix(STCundefined, NULL);
+                TypeFunction *tf = new TypeFunction(parameters, t, varargs, linkage, stc);
+                if (stc & (STCconst | STCimmutable | STCshared | STCwild | STCreturn))
+                {
+                    if (save == TOKfunction)
+                        error("const/immutable/shared/inout/return attributes are only valid for non-static member functions");
+                    else
+                        tf = (TypeFunction *)tf->addSTC(stc);
+                }
+
+                if (save == TOKdelegate)
+                    t = new TypeDelegate(tf);
+                else
+                    t = new TypePointer(tf);    // pointer to function
+                continue;
+            }
+
+            default:
+                return t;
+        }
+        assert(0);
+    }
+    assert(0);
+    return NULL;
+}
+
+Type *Parser::parseDeclarator(Type *t, int *palt, Identifier **pident,
+        TemplateParameters **tpl, StorageClass storageClass, int *pdisable, Expressions **pudas)
+{
+    //printf("parseDeclarator(tpl = %p)\n", tpl);
+    t = parseBasicType2(t);
+
+    Type *ts;
+    switch (token.value)
+    {
+        case TOKidentifier:
+            if (pident)
+                *pident = token.ident;
+            else
+                error("unexpected identifer '%s' in declarator", token.ident->toChars());
+            ts = t;
+            nextToken();
+            break;
+
+        case TOKlparen:
+        {
+            // like: T (*fp)();
+            // like: T ((*fp))();
+            if (peekNext() == TOKmul ||
+                peekNext() == TOKlparen)
+            {
+                /* Parse things with parentheses around the identifier, like:
+                 *  int (*ident[3])[]
+                 * although the D style would be:
+                 *  int[]*[3] ident
+                 */
+                *palt |= 1;
+                nextToken();
+                ts = parseDeclarator(t, palt, pident);
+                check(TOKrparen);
+                break;
+            }
+            ts = t;
+
+            Token *peekt = &token;
+            /* Completely disallow C-style things like:
+             *   T (a);
+             * Improve error messages for the common bug of a missing return type
+             * by looking to see if (a) looks like a parameter list.
+             */
+            if (isParameters(&peekt))
+            {
+                error("function declaration without return type. (Note that constructors are always named 'this')");
+            }
+            else
+                error("unexpected ( in declarator");
+            break;
+        }
+
+        default:
+            ts = t;
+            break;
+    }
+
+    // parse DeclaratorSuffixes
+    while (1)
+    {
+        switch (token.value)
+        {
+#if CARRAYDECL
+            /* Support C style array syntax:
+             *   int ident[]
+             * as opposed to D-style:
+             *   int[] ident
+             */
+            case TOKlbracket:
+            {
+                // This is the old C-style post [] syntax.
+                TypeNext *ta;
+                nextToken();
+                if (token.value == TOKrbracket)
+                {
+                    // It's a dynamic array
+                    ta = new TypeDArray(t);             // []
+                    nextToken();
+                    *palt |= 2;
+                }
+                else if (isDeclaration(&token, 0, TOKrbracket, NULL))
+                {
+                    // It's an associative array
+                    //printf("it's an associative array\n");
+                    Type *index = parseType();          // [ type ]
+                    check(TOKrbracket);
+                    ta = new TypeAArray(t, index);
+                    *palt |= 2;
+                }
+                else
+                {
+                    //printf("It's a static array\n");
+                    Expression *e = parseAssignExp();   // [ expression ]
+                    ta = new TypeSArray(t, e);
+                    check(TOKrbracket);
+                    *palt |= 2;
+                }
+
+                /* Insert ta into
+                 *   ts -> ... -> t
+                 * so that
+                 *   ts -> ... -> ta -> t
+                 */
+                Type **pt;
+                for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next)
+                    ;
+                *pt = ta;
+                continue;
+            }
+#endif
+            case TOKlparen:
+            {
+                if (tpl)
+                {
+                    Token *tk = peekPastParen(&token);
+                    if (tk->value == TOKlparen)
+                    {
+                        /* Look ahead to see if this is (...)(...),
+                         * i.e. a function template declaration
+                         */
+                        //printf("function template declaration\n");
+
+                        // Gather template parameter list
+                        *tpl = parseTemplateParameterList();
+                    }
+                    else if (tk->value == TOKassign)
+                    {
+                        /* or (...) =,
+                         * i.e. a variable template declaration
+                         */
+                        //printf("variable template declaration\n");
+                        *tpl = parseTemplateParameterList();
+                        break;
+                    }
+                }
+
+                int varargs;
+                Parameters *parameters = parseParameters(&varargs);
+
+                /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
+                 */
+                StorageClass stc = parsePostfix(storageClass, pudas);
+                                        // merge prefix storage classes
+                Type *tf = new TypeFunction(parameters, t, varargs, linkage, stc);
+                tf = tf->addSTC(stc);
+                if (pdisable)
+                    *pdisable = stc & STCdisable ? 1 : 0;
+
+                /* Insert tf into
+                 *   ts -> ... -> t
+                 * so that
+                 *   ts -> ... -> tf -> t
+                 */
+                Type **pt;
+                for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next)
+                    ;
+                *pt = tf;
+                break;
+            }
+            default: break;
+        }
+        break;
+    }
+
+    return ts;
+}
+
+void Parser::parseStorageClasses(StorageClass &storage_class, LINK &link,
+    bool &setAlignment, Expression *&ealign, Expressions *&udas)
+{
+    StorageClass stc;
+    bool sawLinkage = false;            // seen a linkage declaration
+
+    while (1)
+    {
+        switch (token.value)
+        {
+            case TOKconst:
+                if (peek(&token)->value == TOKlparen)
+                    break;              // const as type constructor
+                stc = STCconst;         // const as storage class
+                goto L1;
+
+            case TOKimmutable:
+                if (peek(&token)->value == TOKlparen)
+                    break;
+                stc = STCimmutable;
+                goto L1;
+
+            case TOKshared:
+                if (peek(&token)->value == TOKlparen)
+                    break;
+                stc = STCshared;
+                goto L1;
+
+            case TOKwild:
+                if (peek(&token)->value == TOKlparen)
+                    break;
+                stc = STCwild;
+                goto L1;
+
+            case TOKstatic:     stc = STCstatic;         goto L1;
+            case TOKfinal:      stc = STCfinal;          goto L1;
+            case TOKauto:       stc = STCauto;           goto L1;
+            case TOKscope:      stc = STCscope;          goto L1;
+            case TOKoverride:   stc = STCoverride;       goto L1;
+            case TOKabstract:   stc = STCabstract;       goto L1;
+            case TOKsynchronized: stc = STCsynchronized; goto L1;
+            case TOKdeprecated: stc = STCdeprecated;     goto L1;
+            case TOKnothrow:    stc = STCnothrow;        goto L1;
+            case TOKpure:       stc = STCpure;           goto L1;
+            case TOKref:        stc = STCref;            goto L1;
+            case TOKgshared:    stc = STCgshared;        goto L1;
+            case TOKenum:       stc = STCmanifest;       goto L1;
+            case TOKat:
+            {
+                stc = parseAttribute(&udas);
+                if (stc)
+                    goto L1;
+                continue;
+            }
+            L1:
+                storage_class = appendStorageClass(storage_class, stc);
+                nextToken();
+                continue;
+
+            case TOKextern:
+            {
+                if (peek(&token)->value != TOKlparen)
+                {
+                    stc = STCextern;
+                    goto L1;
+                }
+
+                if (sawLinkage)
+                    error("redundant linkage declaration");
+                sawLinkage = true;
+                Identifiers *idents = NULL;
+                CPPMANGLE cppmangle = CPPMANGLEdefault;
+                link = parseLinkage(&idents, &cppmangle);
+                if (idents)
+                {
+                    error("C++ name spaces not allowed here");
+                    delete idents;
+                }
+                if (cppmangle != CPPMANGLEdefault)
+                {
+                     error("C++ mangle declaration not allowed here");
+                }
+                continue;
+            }
+
+            case TOKalign:
+            {
+                nextToken();
+                setAlignment = true;
+                if (token.value == TOKlparen)
+                {
+                    nextToken();
+                    ealign = parseExpression();
+                    check(TOKrparen);
+                }
+                continue;
+            }
+            default:
+                break;
+        }
+        break;
+    }
+}
+
+/**********************************
+ * Parse Declarations.
+ * These can be:
+ *      1. declarations at global/class level
+ *      2. declarations at statement level
+ * Return array of Declaration *'s.
+ */
+
+Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, const utf8_t *comment)
+{
+    StorageClass storage_class = STCundefined;
+    Type *ts;
+    Type *t;
+    Type *tfirst;
+    Identifier *ident;
+    TOK tok = TOKreserved;
+    LINK link = linkage;
+    bool setAlignment = false;
+    Expression *ealign = NULL;
+    Loc loc = token.loc;
+    Expressions *udas = NULL;
+    Token *tk;
+
+    //printf("parseDeclarations() %s\n", token.toChars());
+    if (!comment)
+        comment = token.blockComment;
+
+    if (autodecl)
+    {
+        ts = NULL;              // infer type
+        goto L2;
+    }
+
+    if (token.value == TOKalias)
+    {
+        tok = token.value;
+        nextToken();
+
+        /* Look for:
+         *   alias identifier this;
+         */
+        if (token.value == TOKidentifier && peekNext() == TOKthis)
+        {
+            AliasThis *s = new AliasThis(loc, token.ident);
+            nextToken();
+            check(TOKthis);
+            check(TOKsemicolon);
+            Dsymbols *a = new Dsymbols();
+            a->push(s);
+            addComment(s, comment);
+            return a;
+        }
+#if 0
+        /* Look for:
+         *  alias this = identifier;
+         */
+        if (token.value == TOKthis && peekNext() == TOKassign && peekNext2() == TOKidentifier)
+        {
+            check(TOKthis);
+            check(TOKassign);
+            AliasThis *s = new AliasThis(loc, token.ident);
+            nextToken();
+            check(TOKsemicolon);
+            Dsymbols *a = new Dsymbols();
+            a->push(s);
+            addComment(s, comment);
+            return a;
+        }
+#endif
+        /* Look for:
+         *  alias identifier = type;
+         *  alias identifier(...) = type;
+         */
+        if (token.value == TOKidentifier &&
+            skipParensIf(peek(&token), &tk) &&
+            tk->value == TOKassign)
+        {
+            Dsymbols *a = new Dsymbols();
+            while (1)
+            {
+                ident = token.ident;
+                nextToken();
+                TemplateParameters *tpl = NULL;
+                if (token.value == TOKlparen)
+                    tpl = parseTemplateParameterList();
+                check(TOKassign);
+
+                Declaration *v;
+                if (token.value == TOKfunction ||
+                    token.value == TOKdelegate ||
+                    token.value == TOKlparen &&
+                        skipAttributes(peekPastParen(&token), &tk) &&
+                        (tk->value == TOKgoesto || tk->value == TOKlcurly) ||
+                    token.value == TOKlcurly ||
+                    token.value == TOKidentifier && peekNext() == TOKgoesto
+                   )
+                {
+                    // function (parameters) { statements... }
+                    // delegate (parameters) { statements... }
+                    // (parameters) { statements... }
+                    // (parameters) => expression
+                    // { statements... }
+                    // identifier => expression
+
+                    Dsymbol *s = parseFunctionLiteral();
+                    v = new AliasDeclaration(loc, ident, s);
+                }
+                else
+                {
+                    // StorageClasses type
+
+                    storage_class = STCundefined;
+                    link = linkage;
+                    setAlignment = false;
+                    ealign = NULL;
+                    udas = NULL;
+                    parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
+
+                    if (udas)
+                        error("user defined attributes not allowed for %s declarations", Token::toChars(tok));
+
+                    t = parseType();
+                    v = new AliasDeclaration(loc, ident, t);
+                }
+                v->storage_class = storage_class;
+
+                Dsymbol *s = v;
+                if (tpl)
+                {
+                    Dsymbols *a2 = new Dsymbols();
+                    a2->push(s);
+                    TemplateDeclaration *tempdecl =
+                        new TemplateDeclaration(loc, ident, tpl, NULL, a2);
+                    s = tempdecl;
+                }
+                if (setAlignment)
+                {
+                    Dsymbols *ax = new Dsymbols();
+                    ax->push(s);
+                    s = new AlignDeclaration(v->loc, ealign, ax);
+                }
+                if (link != linkage)
+                {
+                    Dsymbols *a2 = new Dsymbols();
+                    a2->push(s);
+                    s = new LinkDeclaration(link, a2);
+                }
+                a->push(s);
+
+                switch (token.value)
+                {
+                    case TOKsemicolon:
+                        nextToken();
+                        addComment(s, comment);
+                        break;
+                    case TOKcomma:
+                        nextToken();
+                        addComment(s, comment);
+                        if (token.value != TOKidentifier)
+                        {
+                            error("identifier expected following comma, not %s", token.toChars());
+                            break;
+                        }
+                        if (peekNext() != TOKassign && peekNext() != TOKlparen)
+                        {
+                            error("= expected following identifier");
+                            nextToken();
+                            break;
+                        }
+                        continue;
+                    default:
+                        error("semicolon expected to close %s declaration", Token::toChars(tok));
+                        break;
+                }
+                break;
+            }
+            return a;
+        }
+
+        // alias StorageClasses type ident;
+    }
+
+    parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
+
+    if (token.value == TOKstruct ||
+        token.value == TOKunion ||
+        token.value == TOKclass ||
+        token.value == TOKinterface)
+    {
+        Dsymbol *s = parseAggregate();
+        Dsymbols *a = new Dsymbols();
+        a->push(s);
+
+        if (storage_class)
+        {
+            s = new StorageClassDeclaration(storage_class, a);
+            a = new Dsymbols();
+            a->push(s);
+        }
+        if (setAlignment)
+        {
+            s = new AlignDeclaration(s->loc, ealign, a);
+            a = new Dsymbols();
+            a->push(s);
+        }
+        if (link != linkage)
+        {
+            s = new LinkDeclaration(link, a);
+            a = new Dsymbols();
+            a->push(s);
+        }
+        if (udas)
+        {
+            s = new UserAttributeDeclaration(udas, a);
+            a = new Dsymbols();
+            a->push(s);
+        }
+
+        addComment(s, comment);
+        return a;
+    }
+
+    /* Look for auto initializers:
+     *  storage_class identifier = initializer;
+     *  storage_class identifier(...) = initializer;
+     */
+    if ((storage_class || udas) &&
+        token.value == TOKidentifier &&
+        skipParensIf(peek(&token), &tk) &&
+        tk->value == TOKassign)
+    {
+        Dsymbols *a = parseAutoDeclarations(storage_class, comment);
+        if (udas)
+        {
+            Dsymbol *s = new UserAttributeDeclaration(udas, a);
+            a = new Dsymbols();
+            a->push(s);
+        }
+        return a;
+    }
+
+    /* Look for return type inference for template functions.
+     */
+    if ((storage_class || udas) &&
+        token.value == TOKidentifier &&
+        skipParens(peek(&token), &tk) &&
+        skipAttributes(tk, &tk) &&
+        (tk->value == TOKlparen ||
+         tk->value == TOKlcurly ||
+         tk->value == TOKin ||
+         tk->value == TOKout ||
+         tk->value == TOKbody)
+       )
+    {
+        ts = NULL;
+    }
+    else
+    {
+        ts = parseBasicType();
+        ts = parseBasicType2(ts);
+    }
+
+L2:
+    tfirst = NULL;
+    Dsymbols *a = new Dsymbols();
+
+    if (pAttrs)
+    {
+        storage_class |= pAttrs->storageClass;
+        //pAttrs->storageClass = STCundefined;
+    }
+
+    while (1)
+    {
+        TemplateParameters *tpl = NULL;
+        int disable;
+        int alt = 0;
+
+        loc = token.loc;
+        ident = NULL;
+        t = parseDeclarator(ts, &alt, &ident, &tpl, storage_class, &disable, &udas);
+        assert(t);
+        if (!tfirst)
+            tfirst = t;
+        else if (t != tfirst)
+            error("multiple declarations must have the same type, not %s and %s",
+                tfirst->toChars(), t->toChars());
+        bool isThis = (t->ty == Tident && ((TypeIdentifier *)t)->ident == Id::This && token.value == TOKassign);
+        if (ident)
+            checkCstyleTypeSyntax(loc, t, alt, ident);
+        else if (!isThis)
+            error("no identifier for declarator %s", t->toChars());
+
+        if (tok == TOKalias)
+        {
+            Declaration *v;
+            Initializer *init = NULL;
+
+            /* Aliases can no longer have multiple declarators, storage classes,
+             * linkages, or auto declarations.
+             * These never made any sense, anyway.
+             * The code below needs to be fixed to reject them.
+             * The grammar has already been fixed to preclude them.
+             */
+
+            if (udas)
+                error("user defined attributes not allowed for %s declarations", Token::toChars(tok));
+
+            if (token.value == TOKassign)
+            {
+                nextToken();
+                init = parseInitializer();
+            }
+            if (init)
+            {
+                if (isThis)
+                    error("cannot use syntax 'alias this = %s', use 'alias %s this' instead",
+                          init->toChars(), init->toChars());
+                else
+                    error("alias cannot have initializer");
+            }
+            v = new AliasDeclaration(loc, ident, t);
+
+            v->storage_class = storage_class;
+            if (pAttrs)
+            {
+                /* AliasDeclaration distinguish @safe, @system, @trusted atttributes
+                 * on prefix and postfix.
+                 *   @safe alias void function() FP1;
+                 *   alias @safe void function() FP2;    // FP2 is not @safe
+                 *   alias void function() @safe FP3;
+                 */
+                pAttrs->storageClass &= (STCsafe | STCsystem | STCtrusted);
+            }
+            Dsymbol *s = v;
+
+            if (link != linkage)
+            {
+                Dsymbols *ax = new Dsymbols();
+                ax->push(v);
+                s = new LinkDeclaration(link, ax);
+            }
+            a->push(s);
+            switch (token.value)
+            {
+                case TOKsemicolon:
+                    nextToken();
+                    addComment(s, comment);
+                    break;
+
+                case TOKcomma:
+                    nextToken();
+                    addComment(s, comment);
+                    continue;
+
+                default:
+                    error("semicolon expected to close %s declaration", Token::toChars(tok));
+                    break;
+            }
+        }
+        else if (t->ty == Tfunction)
+        {
+            Expression *constraint = NULL;
+
+            //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class);
+            FuncDeclaration *f =
+                new FuncDeclaration(loc, Loc(), ident, storage_class | (disable ? STCdisable : 0), t);
+            if (pAttrs)
+                pAttrs->storageClass = STCundefined;
+            if (tpl)
+                constraint = parseConstraint();
+            Dsymbol *s = parseContracts(f);
+
+            /* A template parameter list means it's a function template
+             */
+            if (tpl)
+            {
+                // Wrap a template around the function declaration
+                Dsymbols *decldefs = new Dsymbols();
+                decldefs->push(s);
+                TemplateDeclaration *tempdecl =
+                    new TemplateDeclaration(loc, s->ident, tpl, constraint, decldefs);
+                s = tempdecl;
+
+                if (storage_class & STCstatic)
+                {
+                    assert(f->storage_class & STCstatic);
+                    f->storage_class &= ~STCstatic;
+
+                    Dsymbols *ax = new Dsymbols();
+                    ax->push(s);
+                    s = new StorageClassDeclaration(STCstatic, ax);
+                }
+            }
+            if (link != linkage)
+            {
+                Dsymbols *ax = new Dsymbols();
+                ax->push(s);
+                s = new LinkDeclaration(link, ax);
+            }
+            if (udas)
+            {
+                Dsymbols *ax = new Dsymbols();
+                ax->push(s);
+                s = new UserAttributeDeclaration(udas, ax);
+            }
+            a->push(s);
+            addComment(s, comment);
+        }
+        else if (ident)
+        {
+            Initializer *init = NULL;
+            if (token.value == TOKassign)
+            {
+                nextToken();
+                init = parseInitializer();
+            }
+
+            VarDeclaration *v = new VarDeclaration(loc, t, ident, init);
+            v->storage_class = storage_class;
+            if (pAttrs)
+                pAttrs->storageClass = STCundefined;
+
+            Dsymbol *s = v;
+
+            if (tpl && init)
+            {
+                Dsymbols *a2 = new Dsymbols();
+                a2->push(s);
+                TemplateDeclaration *tempdecl =
+                    new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0);
+                s = tempdecl;
+            }
+            if (link != linkage)
+            {
+                Dsymbols *ax = new Dsymbols();
+                ax->push(s);
+                s = new LinkDeclaration(link, ax);
+            }
+            if (udas)
+            {
+                Dsymbols *ax = new Dsymbols();
+                ax->push(s);
+                s = new UserAttributeDeclaration(udas, ax);
+            }
+            a->push(s);
+            switch (token.value)
+            {
+                case TOKsemicolon:
+                    nextToken();
+                    addComment(s, comment);
+                    break;
+
+                case TOKcomma:
+                    nextToken();
+                    addComment(s, comment);
+                    continue;
+
+                default:
+                    error("semicolon expected, not '%s'", token.toChars());
+                    break;
+            }
+        }
+        break;
+    }
+    return a;
+}
+
+Dsymbol *Parser::parseFunctionLiteral()
+{
+    Loc loc = token.loc;
+
+    TemplateParameters *tpl = NULL;
+    Parameters *parameters = NULL;
+    int varargs = 0;
+    Type *tret = NULL;
+    StorageClass stc = 0;
+    TOK save = TOKreserved;
+
+    switch (token.value)
+    {
+        case TOKfunction:
+        case TOKdelegate:
+            save = token.value;
+            nextToken();
+            if (token.value != TOKlparen && token.value != TOKlcurly)
+            {
+                // function type (parameters) { statements... }
+                // delegate type (parameters) { statements... }
+                tret = parseBasicType();
+                tret = parseBasicType2(tret);   // function return type
+            }
+
+            if (token.value == TOKlparen)
+            {
+                // function (parameters) { statements... }
+                // delegate (parameters) { statements... }
+            }
+            else
+            {
+                // function { statements... }
+                // delegate { statements... }
+                break;
+            }
+            /* fall through to TOKlparen */
+
+        case TOKlparen:
+        {
+            // (parameters) => expression
+            // (parameters) { statements... }
+            parameters = parseParameters(&varargs, &tpl);
+            stc = parsePostfix(STCundefined, NULL);
+            if (stc & (STCconst | STCimmutable | STCshared | STCwild))
+                error("const/immutable/shared/inout attributes are only valid for non-static member functions");
+            break;
+        }
+        case TOKlcurly:
+            // { statements... }
+            break;
+
+        case TOKidentifier:
+        {
+            // identifier => expression
+            parameters = new Parameters();
+            Identifier *id = Identifier::generateId("__T");
+            Type *t = new TypeIdentifier(loc, id);
+            parameters->push(new Parameter(0, t, token.ident, NULL));
+
+            tpl = new TemplateParameters();
+            TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
+            tpl->push(tp);
+
+            nextToken();
+            break;
+        }
+        default:
+            assert(0);
+    }
+
+    if (!parameters)
+        parameters = new Parameters();
+    TypeFunction *tf = new TypeFunction(parameters, tret, varargs, linkage, stc);
+    FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, Loc(), tf, save, NULL);
+
+    if (token.value == TOKgoesto)
+    {
+        check(TOKgoesto);
+        Loc returnloc = token.loc;
+        Expression *ae = parseAssignExp();
+        fd->fbody = new ReturnStatement(returnloc, ae);
+        fd->endloc = token.loc;
+    }
+    else
+    {
+        parseContracts(fd);
+    }
+
+    if (tpl)
+    {
+        // Wrap a template around function fd
+        Dsymbols *decldefs = new Dsymbols();
+        decldefs->push(fd);
+        return new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, false, true);
+    }
+    else
+        return fd;
+}
+
+/*****************************************
+ * Parse auto declarations of the form:
+ *   storageClass ident = init, ident = init, ... ;
+ * and return the array of them.
+ * Starts with token on the first ident.
+ * Ends with scanner past closing ';'
+ */
+
+Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, const utf8_t *comment)
+{
+    //printf("parseAutoDeclarations\n");
+    Token *tk;
+    Dsymbols *a = new Dsymbols;
+
+    while (1)
+    {
+        Loc loc = token.loc;
+        Identifier *ident = token.ident;
+        nextToken();            // skip over ident
+
+        TemplateParameters *tpl = NULL;
+        if (token.value == TOKlparen)
+            tpl = parseTemplateParameterList();
+
+        assert(token.value == TOKassign);
+        nextToken();            // skip over '='
+        Initializer *init = parseInitializer();
+        VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
+        v->storage_class = storageClass;
+
+        Dsymbol *s = v;
+        if (tpl)
+        {
+            Dsymbols *a2 = new Dsymbols();
+            a2->push(v);
+            TemplateDeclaration *tempdecl =
+                new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0);
+            s = tempdecl;
+        }
+        a->push(s);
+        switch (token.value)
+        {
+            case TOKsemicolon:
+                nextToken();
+                addComment(s, comment);
+                break;
+
+            case TOKcomma:
+                nextToken();
+                if (!(token.value == TOKidentifier &&
+                      skipParensIf(peek(&token), &tk) &&
+                      tk->value == TOKassign))
+                {
+                    error("identifier expected following comma");
+                    break;
+                }
+                addComment(s, comment);
+                continue;
+
+            default:
+                error("semicolon expected following auto declaration, not '%s'", token.toChars());
+                break;
+        }
+        break;
+    }
+    return a;
+}
+
+/*****************************************
+ * Parse contracts following function declaration.
+ */
+
+FuncDeclaration *Parser::parseContracts(FuncDeclaration *f)
+{
+    LINK linksave = linkage;
+
+    bool literal = f->isFuncLiteralDeclaration() != NULL;
+
+    // The following is irrelevant, as it is overridden by sc->linkage in
+    // TypeFunction::semantic
+    linkage = LINKd;            // nested functions have D linkage
+L1:
+    switch (token.value)
+    {
+        case TOKlcurly:
+            if (f->frequire || f->fensure)
+                error("missing body { ... } after in or out");
+            f->fbody = parseStatement(PSsemi);
+            f->endloc = endloc;
+            break;
+
+        case TOKbody:
+            nextToken();
+            f->fbody = parseStatement(PScurly);
+            f->endloc = endloc;
+            break;
+
+#if 0   // Do we want this for function declarations, so we can do:
+    // int x, y, foo(), z;
+        case TOKcomma:
+            nextToken();
+            continue;
+#endif
+
+#if 0 // Dumped feature
+        case TOKthrow:
+            if (!f->fthrows)
+                f->fthrows = new Types();
+            nextToken();
+            check(TOKlparen);
+            while (1)
+            {
+                Type *tb = parseBasicType();
+                f->fthrows->push(tb);
+                if (token.value == TOKcomma)
+                {   nextToken();
+                    continue;
+                }
+                break;
+            }
+            check(TOKrparen);
+            goto L1;
+#endif
+
+        case TOKin:
+            nextToken();
+            if (f->frequire)
+                error("redundant 'in' statement");
+            f->frequire = parseStatement(PScurly | PSscope);
+            goto L1;
+
+        case TOKout:
+            // parse: out (identifier) { statement }
+            nextToken();
+            if (token.value != TOKlcurly)
+            {
+                check(TOKlparen);
+                if (token.value != TOKidentifier)
+                    error("(identifier) following 'out' expected, not %s", token.toChars());
+                f->outId = token.ident;
+                nextToken();
+                check(TOKrparen);
+            }
+            if (f->fensure)
+                error("redundant 'out' statement");
+            f->fensure = parseStatement(PScurly | PSscope);
+            goto L1;
+
+        case TOKsemicolon:
+            if (!literal)
+            {
+                if (f->frequire || f->fensure)
+                    error("missing body { ... } after in or out");
+                nextToken();
+                break;
+            }
+            /* fall through */
+
+        default:
+            if (literal)
+            {
+                const char *sbody = (f->frequire || f->fensure) ? "body " : "";
+                error("missing %s{ ... } for function literal", sbody);
+            }
+            else if (!f->frequire && !f->fensure)   // allow these even with no body
+            {
+                error("semicolon expected following function declaration");
+            }
+            break;
+    }
+    if (literal && !f->fbody)
+    {
+        // Set empty function body for error recovery
+        f->fbody = new CompoundStatement(Loc(), (Statement *)NULL);
+    }
+
+    linkage = linksave;
+
+    return f;
+}
+
+/*****************************************
+ * Parse initializer for variable declaration.
+ */
+
+Initializer *Parser::parseInitializer()
+{
+    StructInitializer *is;
+    ArrayInitializer *ia;
+    ExpInitializer *ie;
+    Expression *e;
+    Identifier *id;
+    Initializer *value;
+    int comma;
+    Loc loc = token.loc;
+    Token *t;
+    int braces;
+    int brackets;
+
+    switch (token.value)
+    {
+        case TOKlcurly:
+            /* Scan ahead to see if it is a struct initializer or
+             * a function literal.
+             * If it contains a ';', it is a function literal.
+             * Treat { } as a struct initializer.
+             */
+            braces = 1;
+            for (t = peek(&token); 1; t = peek(t))
+            {
+                switch (t->value)
+                {
+                    case TOKsemicolon:
+                    case TOKreturn:
+                        goto Lexpression;
+
+                    case TOKlcurly:
+                        braces++;
+                        continue;
+
+                    case TOKrcurly:
+                        if (--braces == 0)
+                            break;
+                        continue;
+
+                    case TOKeof:
+                        break;
+
+                    default:
+                        continue;
+                }
+                break;
+            }
+
+            is = new StructInitializer(loc);
+            nextToken();
+            comma = 2;
+            while (1)
+            {
+                switch (token.value)
+                {
+                    case TOKidentifier:
+                        if (comma == 1)
+                            error("comma expected separating field initializers");
+                        t = peek(&token);
+                        if (t->value == TOKcolon)
+                        {
+                            id = token.ident;
+                            nextToken();
+                            nextToken();        // skip over ':'
+                        }
+                        else
+                        {   id = NULL;
+                        }
+                        value = parseInitializer();
+                        is->addInit(id, value);
+                        comma = 1;
+                        continue;
+
+                    case TOKcomma:
+                        if (comma == 2)
+                            error("expression expected, not ','");
+                        nextToken();
+                        comma = 2;
+                        continue;
+
+                    case TOKrcurly:             // allow trailing comma's
+                        nextToken();
+                        break;
+
+                    case TOKeof:
+                        error("found EOF instead of initializer");
+                        break;
+
+                    default:
+                        if (comma == 1)
+                            error("comma expected separating field initializers");
+                        value = parseInitializer();
+                        is->addInit(NULL, value);
+                        comma = 1;
+                        continue;
+                        //error("found '%s' instead of field initializer", token.toChars());
+                        //break;
+                }
+                break;
+            }
+            return is;
+
+        case TOKlbracket:
+            /* Scan ahead to see if it is an array initializer or
+             * an expression.
+             * If it ends with a ';' ',' or '}', it is an array initializer.
+             */
+            brackets = 1;
+            for (t = peek(&token); 1; t = peek(t))
+            {
+                switch (t->value)
+                {
+                    case TOKlbracket:
+                        brackets++;
+                        continue;
+
+                    case TOKrbracket:
+                        if (--brackets == 0)
+                        {   t = peek(t);
+                            if (t->value != TOKsemicolon &&
+                                t->value != TOKcomma &&
+                                t->value != TOKrbracket &&
+                                t->value != TOKrcurly)
+                                goto Lexpression;
+                            break;
+                        }
+                        continue;
+
+                    case TOKeof:
+                        break;
+
+                    default:
+                        continue;
+                }
+                break;
+            }
+
+            ia = new ArrayInitializer(loc);
+            nextToken();
+            comma = 2;
+            while (1)
+            {
+                switch (token.value)
+                {
+                    default:
+                        if (comma == 1)
+                        {   error("comma expected separating array initializers, not %s", token.toChars());
+                            nextToken();
+                            break;
+                        }
+                        e = parseAssignExp();
+                        if (!e)
+                            break;
+                        if (token.value == TOKcolon)
+                        {
+                            nextToken();
+                            value = parseInitializer();
+                        }
+                        else
+                        {   value = new ExpInitializer(e->loc, e);
+                            e = NULL;
+                        }
+                        ia->addInit(e, value);
+                        comma = 1;
+                        continue;
+
+                    case TOKlcurly:
+                    case TOKlbracket:
+                        if (comma == 1)
+                            error("comma expected separating array initializers, not %s", token.toChars());
+                        value = parseInitializer();
+                        if (token.value == TOKcolon)
+                        {
+                            nextToken();
+                            e = initializerToExpression(value);
+                            value = parseInitializer();
+                        }
+                        else
+                            e = NULL;
+                        ia->addInit(e, value);
+                        comma = 1;
+                        continue;
+
+                    case TOKcomma:
+                        if (comma == 2)
+                            error("expression expected, not ','");
+                        nextToken();
+                        comma = 2;
+                        continue;
+
+                    case TOKrbracket:           // allow trailing comma's
+                        nextToken();
+                        break;
+
+                    case TOKeof:
+                        error("found '%s' instead of array initializer", token.toChars());
+                        break;
+                }
+                break;
+            }
+            return ia;
+
+        case TOKvoid:
+            t = peek(&token);
+            if (t->value == TOKsemicolon || t->value == TOKcomma)
+            {
+                nextToken();
+                return new VoidInitializer(loc);
+            }
+            goto Lexpression;
+
+        default:
+        Lexpression:
+            e = parseAssignExp();
+            ie = new ExpInitializer(loc, e);
+            return ie;
+    }
+}
+
+/*****************************************
+ * Parses default argument initializer expression that is an assign expression,
+ * with special handling for __FILE__, __FILE_FULL_PATH__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
+ */
+
+Expression *Parser::parseDefaultInitExp()
+{
+    if (token.value == TOKfile ||
+        token.value == TOKfilefullpath ||
+        token.value == TOKline ||
+        token.value == TOKmodulestring ||
+        token.value == TOKfuncstring ||
+        token.value == TOKprettyfunc)
+    {
+        Token *t = peek(&token);
+        if (t->value == TOKcomma || t->value == TOKrparen)
+        {
+            Expression *e = NULL;
+            if (token.value == TOKfile)
+                e = new FileInitExp(token.loc, TOKfile);
+            else if (token.value == TOKfilefullpath)
+                e = new FileInitExp(token.loc, TOKfilefullpath);
+            else if (token.value == TOKline)
+                e = new LineInitExp(token.loc);
+            else if (token.value == TOKmodulestring)
+                e = new ModuleInitExp(token.loc);
+            else if (token.value == TOKfuncstring)
+                e = new FuncInitExp(token.loc);
+            else if (token.value == TOKprettyfunc)
+                e = new PrettyFuncInitExp(token.loc);
+            else
+                assert(0);
+            nextToken();
+            return e;
+        }
+    }
+
+    Expression *e = parseAssignExp();
+    return e;
+}
+
+/*****************************************
+ */
+
+void Parser::checkDanglingElse(Loc elseloc)
+{
+    if (token.value != TOKelse &&
+        token.value != TOKcatch &&
+        token.value != TOKfinally &&
+        lookingForElse.linnum != 0)
+    {
+        warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
+    }
+}
+
+void Parser::checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident)
+{
+    if (!alt)
+        return;
+
+    const char *sp = !ident ? "" : " ";
+    const char *s  = !ident ? "" : ident->toChars();
+    if (alt & 1)    // contains C-style function pointer syntax
+        error(loc, "instead of C-style syntax, use D-style '%s%s%s'", t->toChars(), sp, s);
+    else
+        ::warning(loc, "instead of C-style syntax, use D-style syntax '%s%s%s'", t->toChars(), sp, s);
+
+}
+
+/*****************************************
+ * Input:
+ *      flags   PSxxxx
+ * Output:
+ *      pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of first token of next statement
+ */
+
+Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc)
+{
+    Statement *s;
+    Condition *cond;
+    Statement *ifbody;
+    Statement *elsebody;
+    bool isfinal;
+    Loc loc = token.loc;
+
+    //printf("parseStatement()\n");
+
+    if (flags & PScurly && token.value != TOKlcurly)
+        error("statement expected to be { }, not %s", token.toChars());
+
+    switch (token.value)
+    {
+        case TOKidentifier:
+        {   /* A leading identifier can be a declaration, label, or expression.
+             * The easiest case to check first is label:
+             */
+            Token *t = peek(&token);
+            if (t->value == TOKcolon)
+            {   // It's a label
+
+                Identifier *ident = token.ident;
+                nextToken();
+                nextToken();
+                if (token.value == TOKrcurly)
+                    s = NULL;
+                else if (token.value == TOKlcurly)
+                    s = parseStatement(PScurly | PSscope);
+                else
+                    s = parseStatement(PSsemi_ok);
+                s = new LabelStatement(loc, ident, s);
+                break;
+            }
+            // fallthrough to TOKdot
+        }
+        case TOKdot:
+        case TOKtypeof:
+        case TOKvector:
+            if (isDeclaration(&token, 2, TOKreserved, NULL))
+                goto Ldeclaration;
+            else
+                goto Lexp;
+            break;
+
+        case TOKassert:
+        case TOKthis:
+        case TOKsuper:
+        case TOKint32v:
+        case TOKuns32v:
+        case TOKint64v:
+        case TOKuns64v:
+        case TOKint128v:
+        case TOKuns128v:
+        case TOKfloat32v:
+        case TOKfloat64v:
+        case TOKfloat80v:
+        case TOKimaginary32v:
+        case TOKimaginary64v:
+        case TOKimaginary80v:
+        case TOKcharv:
+        case TOKwcharv:
+        case TOKdcharv:
+        case TOKnull:
+        case TOKtrue:
+        case TOKfalse:
+        case TOKstring:
+        case TOKxstring:
+        case TOKlparen:
+        case TOKcast:
+        case TOKmul:
+        case TOKmin:
+        case TOKadd:
+        case TOKtilde:
+        case TOKnot:
+        case TOKplusplus:
+        case TOKminusminus:
+        case TOKnew:
+        case TOKdelete:
+        case TOKdelegate:
+        case TOKfunction:
+        case TOKtypeid:
+        case TOKis:
+        case TOKlbracket:
+        case TOKtraits:
+        case TOKfile:
+        case TOKfilefullpath:
+        case TOKline:
+        case TOKmodulestring:
+        case TOKfuncstring:
+        case TOKprettyfunc:
+        Lexp:
+        {
+            Expression *exp = parseExpression();
+            check(TOKsemicolon, "statement");
+            s = new ExpStatement(loc, exp);
+            break;
+        }
+
+        case TOKstatic:
+        {   // Look ahead to see if it's static assert() or static if()
+
+            Token *t = peek(&token);
+            if (t->value == TOKassert)
+            {
+                s = new StaticAssertStatement(parseStaticAssert());
+                break;
+            }
+            if (t->value == TOKif)
+            {
+                cond = parseStaticIfCondition();
+                goto Lcondition;
+            }
+            if (t->value == TOKimport)
+            {
+                Dsymbols *imports = parseImport();
+                s = new ImportStatement(loc, imports);
+                if (flags & PSscope)
+                    s = new ScopeStatement(loc, s, token.loc);
+                break;
+            }
+            goto Ldeclaration;
+        }
+
+        case TOKfinal:
+            if (peekNext() == TOKswitch)
+            {
+                nextToken();
+                isfinal = true;
+                goto Lswitch;
+            }
+            goto Ldeclaration;
+
+        case TOKwchar: case TOKdchar:
+        case TOKbool: case TOKchar:
+        case TOKint8: case TOKuns8:
+        case TOKint16: case TOKuns16:
+        case TOKint32: case TOKuns32:
+        case TOKint64: case TOKuns64:
+        case TOKint128: case TOKuns128:
+        case TOKfloat32: case TOKfloat64: case TOKfloat80:
+        case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+        case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+        case TOKvoid:
+            // bug 7773: int.max is always a part of expression
+            if (peekNext() == TOKdot)
+                goto Lexp;
+            if (peekNext() == TOKlparen)
+                goto Lexp;
+        case TOKalias:
+        case TOKconst:
+        case TOKauto:
+        case TOKabstract:
+        case TOKextern:
+        case TOKalign:
+        case TOKimmutable:
+        case TOKshared:
+        case TOKwild:
+        case TOKdeprecated:
+        case TOKnothrow:
+        case TOKpure:
+        case TOKref:
+        case TOKgshared:
+        case TOKat:
+        case TOKstruct:
+        case TOKunion:
+        case TOKclass:
+        case TOKinterface:
+        Ldeclaration:
+        {
+            Dsymbols *a = parseDeclarations(false, NULL, NULL);
+            if (a->dim > 1)
+            {
+                Statements *as = new Statements();
+                as->reserve(a->dim);
+                for (size_t i = 0; i < a->dim; i++)
+                {
+                    Dsymbol *d = (*a)[i];
+                    s = new ExpStatement(loc, d);
+                    as->push(s);
+                }
+                s = new CompoundDeclarationStatement(loc, as);
+            }
+            else if (a->dim == 1)
+            {
+                Dsymbol *d = (*a)[0];
+                s = new ExpStatement(loc, d);
+            }
+            else
+                s = new ExpStatement(loc, (Expression *)NULL);
+            if (flags & PSscope)
+                s = new ScopeStatement(loc, s, token.loc);
+            break;
+        }
+
+        case TOKenum:
+        {   /* Determine if this is a manifest constant declaration,
+             * or a conventional enum.
+             */
+            Dsymbol *d;
+            Token *t = peek(&token);
+            if (t->value == TOKlcurly || t->value == TOKcolon)
+                d = parseEnum();
+            else if (t->value != TOKidentifier)
+                goto Ldeclaration;
+            else
+            {
+                t = peek(t);
+                if (t->value == TOKlcurly || t->value == TOKcolon ||
+                    t->value == TOKsemicolon)
+                    d = parseEnum();
+                else
+                    goto Ldeclaration;
+            }
+            s = new ExpStatement(loc, d);
+            if (flags & PSscope)
+                s = new ScopeStatement(loc, s, token.loc);
+            break;
+        }
+
+        case TOKmixin:
+        {   Token *t = peek(&token);
+            if (t->value == TOKlparen)
+            {   // mixin(string)
+                Expression *e = parseAssignExp();
+                check(TOKsemicolon);
+                if (e->op == TOKmixin)
+                {
+                    CompileExp *cpe = (CompileExp *)e;
+                    s = new CompileStatement(loc, cpe->e1);
+                }
+                else
+                {
+                    s = new ExpStatement(loc, e);
+                }
+                break;
+            }
+            Dsymbol *d = parseMixin();
+            s = new ExpStatement(loc, d);
+            if (flags & PSscope)
+                s = new ScopeStatement(loc, s, token.loc);
+            break;
+        }
+
+        case TOKlcurly:
+        {
+            Loc lookingForElseSave = lookingForElse;
+            lookingForElse = Loc();
+
+            nextToken();
+            //if (token.value == TOKsemicolon)
+                //error("use '{ }' for an empty statement, not a ';'");
+            Statements *statements = new Statements();
+            while (token.value != TOKrcurly && token.value != TOKeof)
+            {
+                statements->push(parseStatement(PSsemi | PScurlyscope));
+            }
+            if (endPtr) *endPtr = token.ptr;
+            endloc = token.loc;
+            if (pEndloc)
+            {
+                *pEndloc = token.loc;
+                pEndloc = NULL; // don't set it again
+            }
+            s = new CompoundStatement(loc, statements);
+            if (flags & (PSscope | PScurlyscope))
+                s = new ScopeStatement(loc, s, token.loc);
+            check(TOKrcurly, "compound statement");
+            lookingForElse = lookingForElseSave;
+            break;
+        }
+
+        case TOKwhile:
+        {
+            nextToken();
+            check(TOKlparen);
+            Expression *condition = parseExpression();
+            check(TOKrparen);
+            Loc endloc;
+            Statement *body = parseStatement(PSscope, NULL, &endloc);
+            s = new WhileStatement(loc, condition, body, endloc);
+            break;
+        }
+
+        case TOKsemicolon:
+            if (!(flags & PSsemi_ok))
+            {
+                if (flags & PSsemi)
+                    warning(loc, "use '{ }' for an empty statement, not a ';'");
+                else
+                    error("use '{ }' for an empty statement, not a ';'");
+            }
+            nextToken();
+            s = new ExpStatement(loc, (Expression *)NULL);
+            break;
+
+        case TOKdo:
+        {   Statement *body;
+            Expression *condition;
+
+            nextToken();
+            Loc lookingForElseSave = lookingForElse;
+            lookingForElse = Loc();
+            body = parseStatement(PSscope);
+            lookingForElse = lookingForElseSave;
+            check(TOKwhile);
+            check(TOKlparen);
+            condition = parseExpression();
+            check(TOKrparen);
+            if (token.value == TOKsemicolon)
+                nextToken();
+            else
+                error("terminating ';' required after do-while statement");
+            s = new DoStatement(loc, body, condition, token.loc);
+            break;
+        }
+
+        case TOKfor:
+        {
+            Statement *init;
+            Expression *condition;
+            Expression *increment;
+
+            nextToken();
+            check(TOKlparen);
+            if (token.value == TOKsemicolon)
+            {   init = NULL;
+                nextToken();
+            }
+            else
+            {
+                Loc lookingForElseSave = lookingForElse;
+                lookingForElse = Loc();
+                init = parseStatement(0);
+                lookingForElse = lookingForElseSave;
+            }
+            if (token.value == TOKsemicolon)
+            {
+                condition = NULL;
+                nextToken();
+            }
+            else
+            {
+                condition = parseExpression();
+                check(TOKsemicolon, "for condition");
+            }
+            if (token.value == TOKrparen)
+            {   increment = NULL;
+                nextToken();
+            }
+            else
+            {   increment = parseExpression();
+                check(TOKrparen);
+            }
+            Loc endloc;
+            Statement *body = parseStatement(PSscope, NULL, &endloc);
+            s = new ForStatement(loc, init, condition, increment, body, endloc);
+            break;
+        }
+
+        case TOKforeach:
+        case TOKforeach_reverse:
+        {
+            TOK op = token.value;
+
+            nextToken();
+            check(TOKlparen);
+
+            Parameters *parameters = new Parameters();
+
+            while (1)
+            {
+                Identifier *ai = NULL;
+                Type *at;
+
+                StorageClass storageClass = 0;
+                StorageClass stc = 0;
+            Lagain:
+                if (stc)
+                {
+                    storageClass = appendStorageClass(storageClass, stc);
+                    nextToken();
+                }
+                switch (token.value)
+                {
+                    case TOKref:
+                        stc = STCref;
+                        goto Lagain;
+
+                    case TOKconst:
+                        if (peekNext() != TOKlparen)
+                        {
+                            stc = STCconst;
+                            goto Lagain;
+                        }
+                        break;
+                    case TOKimmutable:
+                        if (peekNext() != TOKlparen)
+                        {
+                            stc = STCimmutable;
+                            goto Lagain;
+                        }
+                        break;
+                    case TOKshared:
+                        if (peekNext() != TOKlparen)
+                        {
+                            stc = STCshared;
+                            goto Lagain;
+                        }
+                        break;
+                    case TOKwild:
+                        if (peekNext() != TOKlparen)
+                        {
+                            stc = STCwild;
+                            goto Lagain;
+                        }
+                        break;
+                    default:
+                        break;
+                }
+                if (token.value == TOKidentifier)
+                {
+                    Token *t = peek(&token);
+                    if (t->value == TOKcomma || t->value == TOKsemicolon)
+                    {   ai = token.ident;
+                        at = NULL;              // infer argument type
+                        nextToken();
+                        goto Larg;
+                    }
+                }
+                at = parseType(&ai);
+                if (!ai)
+                    error("no identifier for declarator %s", at->toChars());
+              Larg:
+                Parameter *p = new Parameter(storageClass, at, ai, NULL);
+                parameters->push(p);
+                if (token.value == TOKcomma)
+                {   nextToken();
+                    continue;
+                }
+                break;
+            }
+            check(TOKsemicolon);
+
+            Expression *aggr = parseExpression();
+            if (token.value == TOKslice && parameters->dim == 1)
+            {
+                Parameter *p = (*parameters)[0];
+                delete parameters;
+                nextToken();
+                Expression *upr = parseExpression();
+                check(TOKrparen);
+                Loc endloc;
+                Statement *body = parseStatement(0, NULL, &endloc);
+                s = new ForeachRangeStatement(loc, op, p, aggr, upr, body, endloc);
+            }
+            else
+            {
+                check(TOKrparen);
+                Loc endloc;
+                Statement *body = parseStatement(0, NULL, &endloc);
+                s = new ForeachStatement(loc, op, parameters, aggr, body, endloc);
+            }
+            break;
+        }
+
+        case TOKif:
+        {
+            Parameter *param = NULL;
+            Expression *condition;
+
+            nextToken();
+            check(TOKlparen);
+
+            StorageClass storageClass = 0;
+            StorageClass stc = 0;
+        LagainStc:
+            if (stc)
+            {
+                storageClass = appendStorageClass(storageClass, stc);
+                nextToken();
+            }
+            switch (token.value)
+            {
+                case TOKref:
+                    stc = STCref;
+                    goto LagainStc;
+                case TOKauto:
+                    stc = STCauto;
+                    goto LagainStc;
+                case TOKconst:
+                    if (peekNext() != TOKlparen)
+                    {
+                        stc = STCconst;
+                        goto LagainStc;
+                    }
+                    break;
+                case TOKimmutable:
+                    if (peekNext() != TOKlparen)
+                    {
+                        stc = STCimmutable;
+                        goto LagainStc;
+                    }
+                    break;
+                case TOKshared:
+                    if (peekNext() != TOKlparen)
+                    {
+                        stc = STCshared;
+                        goto LagainStc;
+                    }
+                    break;
+                case TOKwild:
+                    if (peekNext() != TOKlparen)
+                    {
+                        stc = STCwild;
+                        goto LagainStc;
+                    }
+                    break;
+                default:
+                    break;
+            }
+
+            if (storageClass != 0 &&
+                token.value == TOKidentifier &&
+                peek(&token)->value == TOKassign)
+            {
+                Identifier *ai = token.ident;
+                Type *at = NULL;        // infer parameter type
+                nextToken();
+                check(TOKassign);
+                param = new Parameter(storageClass, at, ai, NULL);
+            }
+            else if (isDeclaration(&token, 2, TOKassign, NULL))
+            {
+                Identifier *ai;
+                Type *at = parseType(&ai);
+                check(TOKassign);
+                param = new Parameter(storageClass, at, ai, NULL);
+            }
+
+            condition = parseExpression();
+            check(TOKrparen);
+            {
+                Loc lookingForElseSave = lookingForElse;
+                lookingForElse = loc;
+                ifbody = parseStatement(PSscope);
+                lookingForElse = lookingForElseSave;
+            }
+            if (token.value == TOKelse)
+            {
+                Loc elseloc = token.loc;
+                nextToken();
+                elsebody = parseStatement(PSscope);
+                checkDanglingElse(elseloc);
+            }
+            else
+                elsebody = NULL;
+            if (condition && ifbody)
+                s = new IfStatement(loc, param, condition, ifbody, elsebody, token.loc);
+            else
+                s = NULL;               // don't propagate parsing errors
+            break;
+        }
+
+        case TOKscope:
+            if (peek(&token)->value != TOKlparen)
+                goto Ldeclaration;              // scope used as storage class
+            nextToken();
+            check(TOKlparen);
+            if (token.value != TOKidentifier)
+            {   error("scope identifier expected");
+                goto Lerror;
+            }
+            else
+            {   TOK t = TOKon_scope_exit;
+                Identifier *id = token.ident;
+
+                if (id == Id::exit)
+                    t = TOKon_scope_exit;
+                else if (id == Id::failure)
+                    t = TOKon_scope_failure;
+                else if (id == Id::success)
+                    t = TOKon_scope_success;
+                else
+                    error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
+                nextToken();
+                check(TOKrparen);
+                Statement *st = parseStatement(PSscope);
+                s = new OnScopeStatement(loc, t, st);
+                break;
+            }
+
+        case TOKdebug:
+            nextToken();
+            if (token.value == TOKassign)
+            {
+                error("debug conditions can only be declared at module scope");
+                nextToken();
+                nextToken();
+                goto Lerror;
+            }
+            cond = parseDebugCondition();
+            goto Lcondition;
+
+        case TOKversion:
+            nextToken();
+            if (token.value == TOKassign)
+            {
+                error("version conditions can only be declared at module scope");
+                nextToken();
+                nextToken();
+                goto Lerror;
+            }
+            cond = parseVersionCondition();
+            goto Lcondition;
+
+        Lcondition:
+            {
+                Loc lookingForElseSave = lookingForElse;
+                lookingForElse = loc;
+                ifbody = parseStatement(0);
+                lookingForElse = lookingForElseSave;
+            }
+            elsebody = NULL;
+            if (token.value == TOKelse)
+            {
+                Loc elseloc = token.loc;
+                nextToken();
+                elsebody = parseStatement(0);
+                checkDanglingElse(elseloc);
+            }
+            s = new ConditionalStatement(loc, cond, ifbody, elsebody);
+            if (flags & PSscope)
+                s = new ScopeStatement(loc, s, token.loc);
+            break;
+
+        case TOKpragma:
+        {   Identifier *ident;
+            Expressions *args = NULL;
+            Statement *body;
+
+            nextToken();
+            check(TOKlparen);
+            if (token.value != TOKidentifier)
+            {   error("pragma(identifier expected");
+                goto Lerror;
+            }
+            ident = token.ident;
+            nextToken();
+            if (token.value == TOKcomma && peekNext() != TOKrparen)
+                args = parseArguments();        // pragma(identifier, args...);
+            else
+                check(TOKrparen);               // pragma(identifier);
+            if (token.value == TOKsemicolon)
+            {   nextToken();
+                body = NULL;
+            }
+            else
+                body = parseStatement(PSsemi);
+            s = new PragmaStatement(loc, ident, args, body);
+            break;
+        }
+
+        case TOKswitch:
+            isfinal = false;
+            goto Lswitch;
+
+        Lswitch:
+        {
+            nextToken();
+            check(TOKlparen);
+            Expression *condition = parseExpression();
+            check(TOKrparen);
+            Statement *body = parseStatement(PSscope);
+            s = new SwitchStatement(loc, condition, body, isfinal);
+            break;
+        }
+
+        case TOKcase:
+        {   Expression *exp;
+            Expressions cases;        // array of Expression's
+            Expression *last = NULL;
+
+            while (1)
+            {
+                nextToken();
+                exp = parseAssignExp();
+                cases.push(exp);
+                if (token.value != TOKcomma)
+                    break;
+            }
+            check(TOKcolon);
+
+            /* case exp: .. case last:
+             */
+            if (token.value == TOKslice)
+            {
+                if (cases.dim > 1)
+                    error("only one case allowed for start of case range");
+                nextToken();
+                check(TOKcase);
+                last = parseAssignExp();
+                check(TOKcolon);
+            }
+
+            if (flags & PScurlyscope)
+            {
+                Statements *statements = new Statements();
+                while (token.value != TOKcase &&
+                       token.value != TOKdefault &&
+                       token.value != TOKeof &&
+                       token.value != TOKrcurly)
+                {
+                    statements->push(parseStatement(PSsemi | PScurlyscope));
+                }
+                s = new CompoundStatement(loc, statements);
+            }
+            else
+                s = parseStatement(PSsemi | PScurlyscope);
+            s = new ScopeStatement(loc, s, token.loc);
+
+            if (last)
+            {
+                s = new CaseRangeStatement(loc, exp, last, s);
+            }
+            else
+            {
+                // Keep cases in order by building the case statements backwards
+                for (size_t i = cases.dim; i; i--)
+                {
+                    exp = cases[i - 1];
+                    s = new CaseStatement(loc, exp, s);
+                }
+            }
+            break;
+        }
+
+        case TOKdefault:
+        {
+            nextToken();
+            check(TOKcolon);
+
+            if (flags & PScurlyscope)
+            {
+                Statements *statements = new Statements();
+                while (token.value != TOKcase &&
+                       token.value != TOKdefault &&
+                       token.value != TOKeof &&
+                       token.value != TOKrcurly)
+                {
+                    statements->push(parseStatement(PSsemi | PScurlyscope));
+                }
+                s = new CompoundStatement(loc, statements);
+            }
+            else
+                s = parseStatement(PSsemi | PScurlyscope);
+            s = new ScopeStatement(loc, s, token.loc);
+            s = new DefaultStatement(loc, s);
+            break;
+        }
+
+        case TOKreturn:
+        {   Expression *exp;
+
+            nextToken();
+            if (token.value == TOKsemicolon)
+                exp = NULL;
+            else
+                exp = parseExpression();
+            check(TOKsemicolon, "return statement");
+            s = new ReturnStatement(loc, exp);
+            break;
+        }
+
+        case TOKbreak:
+        {   Identifier *ident;
+
+            nextToken();
+            if (token.value == TOKidentifier)
+            {   ident = token.ident;
+                nextToken();
+            }
+            else
+                ident = NULL;
+            check(TOKsemicolon, "break statement");
+            s = new BreakStatement(loc, ident);
+            break;
+        }
+
+        case TOKcontinue:
+        {   Identifier *ident;
+
+            nextToken();
+            if (token.value == TOKidentifier)
+            {   ident = token.ident;
+                nextToken();
+            }
+            else
+                ident = NULL;
+            check(TOKsemicolon, "continue statement");
+            s = new ContinueStatement(loc, ident);
+            break;
+        }
+
+        case TOKgoto:
+        {   Identifier *ident;
+
+            nextToken();
+            if (token.value == TOKdefault)
+            {
+                nextToken();
+                s = new GotoDefaultStatement(loc);
+            }
+            else if (token.value == TOKcase)
+            {
+                Expression *exp = NULL;
+
+                nextToken();
+                if (token.value != TOKsemicolon)
+                    exp = parseExpression();
+                s = new GotoCaseStatement(loc, exp);
+            }
+            else
+            {
+                if (token.value != TOKidentifier)
+                {
+                    error("identifier expected following goto");
+                    ident = NULL;
+                }
+                else
+                {
+                    ident = token.ident;
+                    nextToken();
+                }
+                s = new GotoStatement(loc, ident);
+            }
+            check(TOKsemicolon, "goto statement");
+            break;
+        }
+
+        case TOKsynchronized:
+        {   Expression *exp;
+            Statement *body;
+
+            Token *t = peek(&token);
+            if (skipAttributes(t, &t) && t->value == TOKclass)
+                goto Ldeclaration;
+
+            nextToken();
+            if (token.value == TOKlparen)
+            {
+                nextToken();
+                exp = parseExpression();
+                check(TOKrparen);
+            }
+            else
+                exp = NULL;
+            body = parseStatement(PSscope);
+            s = new SynchronizedStatement(loc, exp, body);
+            break;
+        }
+
+        case TOKwith:
+        {   Expression *exp;
+            Statement *body;
+
+            nextToken();
+            check(TOKlparen);
+            exp = parseExpression();
+            check(TOKrparen);
+            body = parseStatement(PSscope);
+            s = new WithStatement(loc, exp, body, token.loc);
+            break;
+        }
+
+        case TOKtry:
+        {   Statement *body;
+            Catches *catches = NULL;
+            Statement *finalbody = NULL;
+
+            nextToken();
+            Loc lookingForElseSave = lookingForElse;
+            lookingForElse = Loc();
+            body = parseStatement(PSscope);
+            lookingForElse = lookingForElseSave;
+            while (token.value == TOKcatch)
+            {
+                Statement *handler;
+                Catch *c;
+                Type *t;
+                Identifier *id;
+                Loc catchloc = token.loc;
+
+                nextToken();
+                if (token.value == TOKlcurly || token.value != TOKlparen)
+                {
+                    t = NULL;
+                    id = NULL;
+                }
+                else
+                {
+                    check(TOKlparen);
+                    id = NULL;
+                    t = parseType(&id);
+                    check(TOKrparen);
+                }
+                handler = parseStatement(0);
+                c = new Catch(catchloc, t, id, handler);
+                if (!catches)
+                    catches = new Catches();
+                catches->push(c);
+            }
+
+            if (token.value == TOKfinally)
+            {   nextToken();
+                finalbody = parseStatement(0);
+            }
+
+            s = body;
+            if (!catches && !finalbody)
+                error("catch or finally expected following try");
+            else
+            {   if (catches)
+                    s = new TryCatchStatement(loc, body, catches);
+                if (finalbody)
+                    s = new TryFinallyStatement(loc, s, finalbody);
+            }
+            break;
+        }
+
+        case TOKthrow:
+        {   Expression *exp;
+
+            nextToken();
+            exp = parseExpression();
+            check(TOKsemicolon, "throw statement");
+            s = new ThrowStatement(loc, exp);
+            break;
+        }
+
+        case TOKasm:
+        {
+            // Parse the asm block into a sequence of AsmStatements,
+            // each AsmStatement is one instruction.
+            // Separate out labels.
+            // Defer parsing of AsmStatements until semantic processing.
+
+            Loc labelloc;
+
+            nextToken();
+            StorageClass stc = parsePostfix(STCundefined, NULL);
+            if (stc & (STCconst | STCimmutable | STCshared | STCwild))
+                error("const/immutable/shared/inout attributes are not allowed on asm blocks");
+
+            check(TOKlcurly);
+            Token *toklist = NULL;
+            Token **ptoklist = &toklist;
+            Identifier *label = NULL;
+            Statements *statements = new Statements();
+            size_t nestlevel = 0;
+            while (1)
+            {
+                switch (token.value)
+                {
+                    case TOKidentifier:
+                        if (!toklist)
+                        {
+                            // Look ahead to see if it is a label
+                            Token *t = peek(&token);
+                            if (t->value == TOKcolon)
+                            {   // It's a label
+                                label = token.ident;
+                                labelloc = token.loc;
+                                nextToken();
+                                nextToken();
+                                continue;
+                            }
+                        }
+                        goto Ldefault;
+
+                    case TOKlcurly:
+                        ++nestlevel;
+                        goto Ldefault;
+
+                    case TOKrcurly:
+                        if (nestlevel > 0)
+                        {
+                            --nestlevel;
+                            goto Ldefault;
+                        }
+
+                        if (toklist || label)
+                        {
+                            error("asm statements must end in ';'");
+                        }
+                        break;
+
+                    case TOKsemicolon:
+                        if (nestlevel != 0)
+                            error("mismatched number of curly brackets");
+
+                        s = NULL;
+                        if (toklist || label)
+                        {
+                            // Create AsmStatement from list of tokens we've saved
+                            s = new AsmStatement(token.loc, toklist);
+                            toklist = NULL;
+                            ptoklist = &toklist;
+                            if (label)
+                            {   s = new LabelStatement(labelloc, label, s);
+                                label = NULL;
+                            }
+                            statements->push(s);
+                        }
+                        nextToken();
+                        continue;
+
+                    case TOKeof:
+                        /* { */
+                        error("matching '}' expected, not end of file");
+                        goto Lerror;
+
+#ifdef IN_GCC
+                    case TOKstring:
+                        // If the first token is a string, parse as extended asm.
+                        if (! toklist)
+                        {
+                            s = parseExtAsm(stc);
+                            statements->push(s);
+                            continue;
+                        }
+                        // ...else, drop through.
+#endif
+
+                    default:
+                    Ldefault:
+                        *ptoklist = Token::alloc();
+                        memcpy(*ptoklist, &token, sizeof(Token));
+                        ptoklist = &(*ptoklist)->next;
+                        *ptoklist = NULL;
+
+                        nextToken();
+                        continue;
+                }
+                break;
+            }
+            s = new CompoundAsmStatement(loc, statements, stc);
+            nextToken();
+            break;
+        }
+
+        case TOKimport:
+        {
+            Dsymbols *imports = parseImport();
+            s = new ImportStatement(loc, imports);
+            if (flags & PSscope)
+                s = new ScopeStatement(loc, s, token.loc);
+            break;
+        }
+
+        case TOKtemplate:
+        {
+            Dsymbol *d = parseTemplateDeclaration();
+            s = new ExpStatement(loc, d);
+            break;
+        }
+
+        default:
+            error("found '%s' instead of statement", token.toChars());
+            goto Lerror;
+
+        Lerror:
+            while (token.value != TOKrcurly &&
+                   token.value != TOKsemicolon &&
+                   token.value != TOKeof)
+                nextToken();
+            if (token.value == TOKsemicolon)
+                nextToken();
+            s = NULL;
+            break;
+    }
+    if (pEndloc)
+        *pEndloc = token.loc;
+    return s;
+}
+
+#ifdef IN_GCC
+/***********************************
+ * Parse list of extended asm input or output operands.
+ * ExtAsmOperand:
+ *     [Identifier] StringLiteral (Identifier), ...
+ */
+int Parser::parseExtAsmOperands(Expressions *args, Identifiers *names, Expressions *constraints)
+{
+    int numargs = 0;
+
+    while (1)
+    {
+        Expression *arg = NULL;
+        Identifier *name = NULL;
+        Expression *constraint = NULL;
+
+        switch (token.value)
+        {
+            case TOKsemicolon:
+            case TOKcolon:
+            case TOKeof:
+                return numargs;
+
+            case TOKlbracket:
+                nextToken();
+                if (token.value == TOKidentifier)
+                {
+                    name = token.ident;
+                    nextToken();
+                }
+                else
+                {
+                    error("expected identifier after '['");
+                    return numargs;
+                }
+                check(TOKrbracket);
+                // fall through
+
+            default:
+                constraint = parsePrimaryExp();
+                if (constraint->op != TOKstring)
+                {
+                    error(constraint->loc, "expected constant string constraint for operand, not '%s'", constraint->toChars());
+                    goto Lerror;
+                }
+                arg = parseAssignExp();
+
+                args->push(arg);
+                names->push(name);
+                constraints->push(constraint);
+                numargs++;
+
+                if (token.value == TOKcomma)
+                    nextToken();
+                break;
+        }
+    }
+Lerror:
+    while (token.value != TOKrcurly &&
+           token.value != TOKsemicolon &&
+           token.value != TOKeof)
+        nextToken();
+
+    return numargs;
+}
+
+/***********************************
+ * Parse list of extended asm clobbers.
+ * ExtAsmClobbers:
+ *     StringLiteral, ...
+ */
+Expressions *Parser::parseExtAsmClobbers()
+{
+    Expressions *clobbers = NULL;
+
+    while (1)
+    {
+        Expression *clobber;
+
+        switch (token.value)
+        {
+            case TOKsemicolon:
+            case TOKcolon:
+            case TOKeof:
+                return clobbers;
+
+            case TOKstring:
+                clobber = parseAssignExp();
+                if (!clobbers)
+                    clobbers = new Expressions;
+                clobbers->push(clobber);
+
+                if (token.value == TOKcomma)
+                    nextToken();
+                break;
+
+            default:
+                error("expected constant string constraint for clobber name, not '%s'", token.toChars());
+                goto Lerror;
+        }
+    }
+Lerror:
+    while (token.value != TOKrcurly &&
+           token.value != TOKsemicolon &&
+           token.value != TOKeof)
+        nextToken();
+
+    return clobbers;
+}
+
+/***********************************
+ * Parse list of extended asm goto labels.
+ * ExtAsmGotoLabels:
+ *     Identifier, ...
+ */
+Identifiers *Parser::parseExtAsmGotoLabels()
+{
+    Identifiers *labels = NULL;
+
+    while (1)
+    {
+        switch (token.value)
+        {
+            case TOKsemicolon:
+            case TOKeof:
+                return labels;
+
+            case TOKidentifier:
+                if (!labels)
+                    labels = new Identifiers();
+                labels->push(token.ident);
+
+                if (nextToken() == TOKcomma)
+                    nextToken();
+                break;
+
+            default:
+                error("expected identifier for goto label name, not '%s'", token.toChars());
+                goto Lerror;
+        }
+    }
+Lerror:
+    while (token.value != TOKrcurly &&
+           token.value != TOKsemicolon &&
+           token.value != TOKeof)
+        nextToken();
+
+    return labels;
+}
+
+/***********************************
+ * Parse an extended asm statement.
+ * ExtAsmStatement:
+ *     asm { StringLiterals [ : InputOperands [ : OutputOperands [ : Clobbers [ : GotoLabels ] ] ] ] }
+ */
+
+Statement *Parser::parseExtAsm(StorageClass stc)
+{
+    Expressions *args = NULL;
+    Identifiers *names = NULL;
+    Expressions *constraints = NULL;
+    int outputargs = 0;
+    Expressions *clobbers = NULL;
+    Identifiers *labels = NULL;
+    Loc loc = token.loc;
+
+    Expression *insn = parseExpression();
+    if (token.value == TOKsemicolon)
+        goto Ldone;
+
+    for (int section = 0; section < 4; ++section)
+    {
+        check(TOKcolon);
+
+        switch (section)
+        {
+            case 0:
+                if (!args)
+                {
+                    args = new Expressions;
+                    constraints = new Expressions;
+                    names = new Identifiers;
+                }
+                outputargs = parseExtAsmOperands(args, names, constraints);
+                break;
+
+            case 1:
+                parseExtAsmOperands(args, names, constraints);
+                break;
+
+            case 2:
+                clobbers = parseExtAsmClobbers();
+                break;
+
+            case 3:
+                labels = parseExtAsmGotoLabels();
+                break;
+
+            default:
+                assert(0);
+        }
+
+        switch (token.value)
+        {
+            case TOKsemicolon:
+                goto Ldone;
+
+            case TOKeof:
+                error("matching '}' expected, not end of file");
+                goto Ldone;
+
+            default:
+                continue;
+        }
+    }
+  Ldone:
+    check(TOKsemicolon);
+
+    return new ExtAsmStatement(loc, stc, insn, args, names,
+                               constraints, outputargs, clobbers, labels);
+}
+#endif
+
+void Parser::check(TOK value)
+{
+    check(token.loc, value);
+}
+
+void Parser::check(Loc loc, TOK value)
+{
+    if (token.value != value)
+        error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
+    nextToken();
+}
+
+void Parser::check(TOK value, const char *string)
+{
+    if (token.value != value)
+        error("found '%s' when expecting '%s' following %s",
+            token.toChars(), Token::toChars(value), string);
+    nextToken();
+}
+
+void Parser::checkParens(TOK value, Expression *e)
+{
+    if (precedence[e->op] == PREC_rel && !e->parens)
+        error(e->loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value));
+}
+
+/************************************
+ * Determine if the scanner is sitting on the start of a declaration.
+ * Input:
+ *      needId  0       no identifier
+ *              1       identifier optional
+ *              2       must have identifier
+ * Output:
+ *      if *pt is not NULL, it is set to the ending token, which would be endtok
+ */
+
+bool Parser::isDeclaration(Token *t, int needId, TOK endtok, Token **pt)
+{
+    //printf("isDeclaration(needId = %d)\n", needId);
+    int haveId = 0;
+    int haveTpl = 0;
+
+    while (1)
+    {
+        if ((t->value == TOKconst ||
+             t->value == TOKimmutable ||
+             t->value == TOKwild ||
+             t->value == TOKshared) &&
+            peek(t)->value != TOKlparen)
+        {
+            /* const type
+             * immutable type
+             * shared type
+             * wild type
+             */
+            t = peek(t);
+            continue;
+        }
+        break;
+    }
+
+    if (!isBasicType(&t))
+    {
+        goto Lisnot;
+    }
+    if (!isDeclarator(&t, &haveId, &haveTpl, endtok))
+        goto Lisnot;
+    if ( needId == 1 ||
+        (needId == 0 && !haveId) ||
+        (needId == 2 &&  haveId))
+    {
+        if (pt)
+            *pt = t;
+        goto Lis;
+    }
+    else
+        goto Lisnot;
+
+Lis:
+    //printf("\tis declaration, t = %s\n", t->toChars());
+    return true;
+
+Lisnot:
+    //printf("\tis not declaration\n");
+    return false;
+}
+
+bool Parser::isBasicType(Token **pt)
+{
+    // This code parallels parseBasicType()
+    Token *t = *pt;
+
+    switch (t->value)
+    {
+        case TOKwchar: case TOKdchar:
+        case TOKbool: case TOKchar:
+        case TOKint8: case TOKuns8:
+        case TOKint16: case TOKuns16:
+        case TOKint32: case TOKuns32:
+        case TOKint64: case TOKuns64:
+        case TOKint128: case TOKuns128:
+        case TOKfloat32: case TOKfloat64: case TOKfloat80:
+        case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+        case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+        case TOKvoid:
+            t = peek(t);
+            break;
+
+        case TOKidentifier:
+        L5:
+            t = peek(t);
+            if (t->value == TOKnot)
+            {
+                goto L4;
+            }
+            goto L3;
+            while (1)
+            {
+        L2:
+                t = peek(t);
+        L3:
+                if (t->value == TOKdot)
+                {
+        Ldot:
+                    t = peek(t);
+                    if (t->value != TOKidentifier)
+                        goto Lfalse;
+                    t = peek(t);
+                    if (t->value != TOKnot)
+                        goto L3;
+        L4:
+                    /* Seen a !
+                     * Look for:
+                     * !( args ), !identifier, etc.
+                     */
+                    t = peek(t);
+                    switch (t->value)
+                    {
+                        case TOKidentifier:
+                            goto L5;
+                        case TOKlparen:
+                            if (!skipParens(t, &t))
+                                goto Lfalse;
+                            goto L3;
+                        case TOKwchar: case TOKdchar:
+                        case TOKbool: case TOKchar:
+                        case TOKint8: case TOKuns8:
+                        case TOKint16: case TOKuns16:
+                        case TOKint32: case TOKuns32:
+                        case TOKint64: case TOKuns64:
+                        case TOKint128: case TOKuns128:
+                        case TOKfloat32: case TOKfloat64: case TOKfloat80:
+                        case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+                        case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+                        case TOKvoid:
+                        case TOKint32v:
+                        case TOKuns32v:
+                        case TOKint64v:
+                        case TOKuns64v:
+                        case TOKint128v:
+                        case TOKuns128v:
+                        case TOKfloat32v:
+                        case TOKfloat64v:
+                        case TOKfloat80v:
+                        case TOKimaginary32v:
+                        case TOKimaginary64v:
+                        case TOKimaginary80v:
+                        case TOKnull:
+                        case TOKtrue:
+                        case TOKfalse:
+                        case TOKcharv:
+                        case TOKwcharv:
+                        case TOKdcharv:
+                        case TOKstring:
+                        case TOKxstring:
+                        case TOKfile:
+                        case TOKfilefullpath:
+                        case TOKline:
+                        case TOKmodulestring:
+                        case TOKfuncstring:
+                        case TOKprettyfunc:
+                            goto L2;
+                        default:
+                            goto Lfalse;
+                    }
+                }
+                else
+                    break;
+            }
+            break;
+
+        case TOKdot:
+            goto Ldot;
+
+        case TOKtypeof:
+        case TOKvector:
+            /* typeof(exp).identifier...
+             */
+            t = peek(t);
+            if (!skipParens(t, &t))
+                goto Lfalse;
+            goto L3;
+
+        case TOKconst:
+        case TOKimmutable:
+        case TOKshared:
+        case TOKwild:
+            // const(type)  or  immutable(type)  or  shared(type)  or  wild(type)
+            t = peek(t);
+            if (t->value != TOKlparen)
+                goto Lfalse;
+            t = peek(t);
+            if (!isDeclaration(t, 0, TOKrparen, &t))
+            {
+                goto Lfalse;
+            }
+            t = peek(t);
+            break;
+
+        default:
+            goto Lfalse;
+    }
+    *pt = t;
+    //printf("is\n");
+    return true;
+
+Lfalse:
+    //printf("is not\n");
+    return false;
+}
+
+bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok)
+{   // This code parallels parseDeclarator()
+    Token *t = *pt;
+    int parens;
+
+    //printf("Parser::isDeclarator() %s\n", t->toChars());
+    if (t->value == TOKassign)
+        return false;
+
+    while (1)
+    {
+        parens = false;
+        switch (t->value)
+        {
+            case TOKmul:
+            //case TOKand:
+                t = peek(t);
+                continue;
+
+            case TOKlbracket:
+                t = peek(t);
+                if (t->value == TOKrbracket)
+                {
+                    t = peek(t);
+                }
+                else if (isDeclaration(t, 0, TOKrbracket, &t))
+                {
+                    // It's an associative array declaration
+                    t = peek(t);
+
+                    // ...[type].ident
+                    if (t->value == TOKdot && peek(t)->value == TOKidentifier)
+                    {
+                        t = peek(t);
+                        t = peek(t);
+                    }
+                }
+                else
+                {
+                    // [ expression ]
+                    // [ expression .. expression ]
+                    if (!isExpression(&t))
+                        return false;
+                    if (t->value == TOKslice)
+                    {
+                        t = peek(t);
+                        if (!isExpression(&t))
+                            return false;
+                        if (t->value != TOKrbracket)
+                            return false;
+                        t = peek(t);
+                    }
+                    else
+                    {
+                        if (t->value != TOKrbracket)
+                            return false;
+                        t = peek(t);
+
+                        // ...[index].ident
+                        if (t->value == TOKdot && peek(t)->value == TOKidentifier)
+                        {
+                            t = peek(t);
+                            t = peek(t);
+                        }
+                    }
+                }
+                continue;
+
+            case TOKidentifier:
+                if (*haveId)
+                    return false;
+                *haveId = true;
+                t = peek(t);
+                break;
+
+            case TOKlparen:
+                t = peek(t);
+
+                if (t->value == TOKrparen)
+                    return false;               // () is not a declarator
+
+                /* Regard ( identifier ) as not a declarator
+                 * BUG: what about ( *identifier ) in
+                 *      f(*p)(x);
+                 * where f is a class instance with overloaded () ?
+                 * Should we just disallow C-style function pointer declarations?
+                 */
+                if (t->value == TOKidentifier)
+                {   Token *t2 = peek(t);
+                    if (t2->value == TOKrparen)
+                        return false;
+                }
+
+
+                if (!isDeclarator(&t, haveId, NULL, TOKrparen))
+                    return false;
+                t = peek(t);
+                parens = true;
+                break;
+
+            case TOKdelegate:
+            case TOKfunction:
+                t = peek(t);
+                if (!isParameters(&t))
+                    return false;
+                skipAttributes(t, &t);
+                continue;
+            default: break;
+        }
+        break;
+    }
+
+    while (1)
+    {
+        switch (t->value)
+        {
+#if CARRAYDECL
+            case TOKlbracket:
+                parens = false;
+                t = peek(t);
+                if (t->value == TOKrbracket)
+                {
+                    t = peek(t);
+                }
+                else if (isDeclaration(t, 0, TOKrbracket, &t))
+                {   // It's an associative array declaration
+                    t = peek(t);
+                }
+                else
+                {
+                    // [ expression ]
+                    if (!isExpression(&t))
+                        return false;
+                    if (t->value != TOKrbracket)
+                        return false;
+                    t = peek(t);
+                }
+                continue;
+#endif
+
+            case TOKlparen:
+                parens = false;
+                if (Token *tk = peekPastParen(t))
+                {
+                    if (tk->value == TOKlparen)
+                    {
+                        if (!haveTpl) return false;
+                        *haveTpl = 1;
+                        t = tk;
+                    }
+                    else if (tk->value == TOKassign)
+                    {
+                        if (!haveTpl) return false;
+                        *haveTpl = 1;
+                        *pt = tk;
+                        return true;
+                    }
+                }
+                if (!isParameters(&t))
+                    return false;
+                while (1)
+                {
+                    switch (t->value)
+                    {
+                        case TOKconst:
+                        case TOKimmutable:
+                        case TOKshared:
+                        case TOKwild:
+                        case TOKpure:
+                        case TOKnothrow:
+                        case TOKreturn:
+                        case TOKscope:
+                            t = peek(t);
+                            continue;
+                        case TOKat:
+                            t = peek(t);        // skip '@'
+                            t = peek(t);        // skip identifier
+                            continue;
+                        default:
+                            break;
+                    }
+                    break;
+                }
+                continue;
+
+            // Valid tokens that follow a declaration
+            case TOKrparen:
+            case TOKrbracket:
+            case TOKassign:
+            case TOKcomma:
+            case TOKdotdotdot:
+            case TOKsemicolon:
+            case TOKlcurly:
+            case TOKin:
+            case TOKout:
+            case TOKbody:
+                // The !parens is to disallow unnecessary parentheses
+                if (!parens && (endtok == TOKreserved || endtok == t->value))
+                {   *pt = t;
+                    return true;
+                }
+                return false;
+            case TOKif:
+                return haveTpl ? true : false;
+
+            default:
+                return false;
+        }
+    }
+}
+
+
+bool Parser::isParameters(Token **pt)
+{   // This code parallels parseParameters()
+    Token *t = *pt;
+
+    //printf("isParameters()\n");
+    if (t->value != TOKlparen)
+        return false;
+
+    t = peek(t);
+    for (;1; t = peek(t))
+    {
+     L1:
+        switch (t->value)
+        {
+            case TOKrparen:
+                break;
+
+            case TOKdotdotdot:
+                t = peek(t);
+                break;
+
+            case TOKin:
+            case TOKout:
+            case TOKref:
+            case TOKlazy:
+            case TOKscope:
+            case TOKfinal:
+            case TOKauto:
+            case TOKreturn:
+                continue;
+
+            case TOKconst:
+            case TOKimmutable:
+            case TOKshared:
+            case TOKwild:
+                t = peek(t);
+                if (t->value == TOKlparen)
+                {
+                    t = peek(t);
+                    if (!isDeclaration(t, 0, TOKrparen, &t))
+                        return false;
+                    t = peek(t);        // skip past closing ')'
+                    goto L2;
+                }
+                goto L1;
+
+#if 0
+            case TOKstatic:
+                continue;
+            case TOKauto:
+            case TOKalias:
+                t = peek(t);
+                if (t->value == TOKidentifier)
+                    t = peek(t);
+                if (t->value == TOKassign)
+                {   t = peek(t);
+                    if (!isExpression(&t))
+                        return false;
+                }
+                goto L3;
+#endif
+
+            default:
+            {   if (!isBasicType(&t))
+                    return false;
+            L2:
+                int tmp = false;
+                if (t->value != TOKdotdotdot &&
+                    !isDeclarator(&t, &tmp, NULL, TOKreserved))
+                    return false;
+                if (t->value == TOKassign)
+                {   t = peek(t);
+                    if (!isExpression(&t))
+                        return false;
+                }
+                if (t->value == TOKdotdotdot)
+                {
+                    t = peek(t);
+                    break;
+                }
+            }
+                if (t->value == TOKcomma)
+                {
+                    continue;
+                }
+                break;
+        }
+        break;
+    }
+    if (t->value != TOKrparen)
+        return false;
+    t = peek(t);
+    *pt = t;
+    return true;
+}
+
+bool Parser::isExpression(Token **pt)
+{
+    // This is supposed to determine if something is an expression.
+    // What it actually does is scan until a closing right bracket
+    // is found.
+
+    Token *t = *pt;
+    int brnest = 0;
+    int panest = 0;
+    int curlynest = 0;
+
+    for (;; t = peek(t))
+    {
+        switch (t->value)
+        {
+            case TOKlbracket:
+                brnest++;
+                continue;
+
+            case TOKrbracket:
+                if (--brnest >= 0)
+                    continue;
+                break;
+
+            case TOKlparen:
+                panest++;
+                continue;
+
+            case TOKcomma:
+                if (brnest || panest)
+                    continue;
+                break;
+
+            case TOKrparen:
+                if (--panest >= 0)
+                    continue;
+                break;
+
+            case TOKlcurly:
+                curlynest++;
+                continue;
+
+            case TOKrcurly:
+                if (--curlynest >= 0)
+                    continue;
+                return false;
+
+            case TOKslice:
+                if (brnest)
+                    continue;
+                break;
+
+            case TOKsemicolon:
+                if (curlynest)
+                    continue;
+                return false;
+
+            case TOKeof:
+                return false;
+
+            default:
+                continue;
+        }
+        break;
+    }
+
+    *pt = t;
+    return true;
+}
+
+/*******************************************
+ * Skip parens, brackets.
+ * Input:
+ *      t is on opening (
+ * Output:
+ *      *pt is set to closing token, which is ')' on success
+ * Returns:
+ *      true    successful
+ *      false   some parsing error
+ */
+
+bool Parser::skipParens(Token *t, Token **pt)
+{
+    if (t->value != TOKlparen)
+        return false;
+
+    int parens = 0;
+
+    while (1)
+    {
+        switch (t->value)
+        {
+            case TOKlparen:
+                parens++;
+                break;
+
+            case TOKrparen:
+                parens--;
+                if (parens < 0)
+                    goto Lfalse;
+                if (parens == 0)
+                    goto Ldone;
+                break;
+
+            case TOKeof:
+                goto Lfalse;
+
+             default:
+                break;
+        }
+        t = peek(t);
+    }
+
+  Ldone:
+    if (pt)
+        *pt = peek(t);  // skip found rparen
+    return true;
+
+  Lfalse:
+    return false;
+}
+
+bool Parser::skipParensIf(Token *t, Token **pt)
+{
+    if (t->value != TOKlparen)
+    {
+        if (pt)
+            *pt = t;
+        return true;
+    }
+    return skipParens(t, pt);
+}
+
+/*******************************************
+ * Skip attributes.
+ * Input:
+ *      t is on a candidate attribute
+ * Output:
+ *      *pt is set to first non-attribute token on success
+ * Returns:
+ *      true    successful
+ *      false   some parsing error
+ */
+
+bool Parser::skipAttributes(Token *t, Token **pt)
+{
+    while (1)
+    {
+        switch (t->value)
+        {
+            case TOKconst:
+            case TOKimmutable:
+            case TOKshared:
+            case TOKwild:
+            case TOKfinal:
+            case TOKauto:
+            case TOKscope:
+            case TOKoverride:
+            case TOKabstract:
+            case TOKsynchronized:
+                break;
+            case TOKdeprecated:
+                if (peek(t)->value == TOKlparen)
+                {
+                    t = peek(t);
+                    if (!skipParens(t, &t))
+                        goto Lerror;
+                    // t is on the next of closing parenthesis
+                    continue;
+                }
+                break;
+            case TOKnothrow:
+            case TOKpure:
+            case TOKref:
+            case TOKgshared:
+            case TOKreturn:
+            //case TOKmanifest:
+                break;
+            case TOKat:
+                t = peek(t);
+                if (t->value == TOKidentifier)
+                {
+                    /* @identifier
+                     * @identifier!arg
+                     * @identifier!(arglist)
+                     * any of the above followed by (arglist)
+                     * @predefined_attribute
+                     */
+                    if (t->ident == Id::property ||
+                        t->ident == Id::nogc ||
+                        t->ident == Id::safe ||
+                        t->ident == Id::trusted ||
+                        t->ident == Id::system ||
+                        t->ident == Id::disable)
+                        break;
+                    t = peek(t);
+                    if (t->value == TOKnot)
+                    {
+                        t = peek(t);
+                        if (t->value == TOKlparen)
+                        {
+                            // @identifier!(arglist)
+                            if (!skipParens(t, &t))
+                                goto Lerror;
+                            // t is on the next of closing parenthesis
+                        }
+                        else
+                        {
+                            // @identifier!arg
+                            // Do low rent skipTemplateArgument
+                            if (t->value == TOKvector)
+                            {
+                                // identifier!__vector(type)
+                                t = peek(t);
+                                if (!skipParens(t, &t))
+                                    goto Lerror;
+                            }
+                            else
+                                t = peek(t);
+                        }
+                    }
+                    if (t->value == TOKlparen)
+                    {
+                        if (!skipParens(t, &t))
+                            goto Lerror;
+                        // t is on the next of closing parenthesis
+                        continue;
+                    }
+                    continue;
+                }
+                if (t->value == TOKlparen)
+                {
+                    // @( ArgumentList )
+                    if (!skipParens(t, &t))
+                        goto Lerror;
+                    // t is on the next of closing parenthesis
+                    continue;
+                }
+                goto Lerror;
+            default:
+                goto Ldone;
+        }
+        t = peek(t);
+    }
+
+  Ldone:
+    if (pt)
+        *pt = t;
+    return true;
+
+  Lerror:
+    return false;
+}
+
+/********************************* Expression Parser ***************************/
+
+Expression *Parser::parsePrimaryExp()
+{
+    Expression *e;
+    Type *t;
+    Identifier *id;
+    Loc loc = token.loc;
+
+    //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
+    switch (token.value)
+    {
+        case TOKidentifier:
+        {
+            if (peekNext() == TOKgoesto)
+                goto case_delegate;
+
+            id = token.ident;
+            nextToken();
+            TOK save;
+            if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin)
+            {
+                // identifier!(template-argument-list)
+                TemplateInstance *tempinst;
+                tempinst = new TemplateInstance(loc, id);
+                tempinst->tiargs = parseTemplateArguments();
+                e = new ScopeExp(loc, tempinst);
+            }
+            else
+                e = new IdentifierExp(loc, id);
+            break;
+        }
+
+        case TOKdollar:
+            if (!inBrackets)
+                error("'$' is valid only inside [] of index or slice");
+            e = new DollarExp(loc);
+            nextToken();
+            break;
+
+        case TOKdot:
+            // Signal global scope '.' operator with "" identifier
+            e = new IdentifierExp(loc, Id::empty);
+            break;
+
+        case TOKthis:
+            e = new ThisExp(loc);
+            nextToken();
+            break;
+
+        case TOKsuper:
+            e = new SuperExp(loc);
+            nextToken();
+            break;
+
+        case TOKint32v:
+            e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32);
+            nextToken();
+            break;
+
+        case TOKuns32v:
+            e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32);
+            nextToken();
+            break;
+
+        case TOKint64v:
+            e = new IntegerExp(loc, token.int64value, Type::tint64);
+            nextToken();
+            break;
+
+        case TOKuns64v:
+            e = new IntegerExp(loc, token.uns64value, Type::tuns64);
+            nextToken();
+            break;
+
+        case TOKfloat32v:
+            e = new RealExp(loc, token.floatvalue, Type::tfloat32);
+            nextToken();
+            break;
+
+        case TOKfloat64v:
+            e = new RealExp(loc, token.floatvalue, Type::tfloat64);
+            nextToken();
+            break;
+
+        case TOKfloat80v:
+            e = new RealExp(loc, token.floatvalue, Type::tfloat80);
+            nextToken();
+            break;
+
+        case TOKimaginary32v:
+            e = new RealExp(loc, token.floatvalue, Type::timaginary32);
+            nextToken();
+            break;
+
+        case TOKimaginary64v:
+            e = new RealExp(loc, token.floatvalue, Type::timaginary64);
+            nextToken();
+            break;
+
+        case TOKimaginary80v:
+            e = new RealExp(loc, token.floatvalue, Type::timaginary80);
+            nextToken();
+            break;
+
+        case TOKnull:
+            e = new NullExp(loc);
+            nextToken();
+            break;
+
+        case TOKfile:
+        {
+            const char *s = loc.filename ? loc.filename : mod->ident->toChars();
+            e = new StringExp(loc, (char *)s, strlen(s), 0);
+            nextToken();
+            break;
+        }
+
+        case TOKfilefullpath:
+        {
+            const char *srcfile = mod->srcfile->name->toChars();
+            const char *s;
+            if (loc.filename && !FileName::equals(loc.filename, srcfile))
+                s = loc.filename;
+            else
+                s = FileName::combine(mod->srcfilePath, srcfile);
+            e = new StringExp(loc, (char *)s, strlen(s), 0);
+            nextToken();
+            break;
+        }
+
+        case TOKline:
+            e = new IntegerExp(loc, loc.linnum, Type::tint32);
+            nextToken();
+            break;
+
+        case TOKmodulestring:
+        {
+            const char *s = md ? md->toChars() : mod->toChars();
+            e = new StringExp(loc, (char *)s, strlen(s), 0);
+            nextToken();
+            break;
+        }
+
+        case TOKfuncstring:
+            e = new FuncInitExp(loc);
+            nextToken();
+            break;
+
+        case TOKprettyfunc:
+            e = new PrettyFuncInitExp(loc);
+            nextToken();
+            break;
+
+        case TOKtrue:
+            e = new IntegerExp(loc, 1, Type::tbool);
+            nextToken();
+            break;
+
+        case TOKfalse:
+            e = new IntegerExp(loc, 0, Type::tbool);
+            nextToken();
+            break;
+
+        case TOKcharv:
+            e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar);
+            nextToken();
+            break;
+
+        case TOKwcharv:
+            e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar);
+            nextToken();
+            break;
+
+        case TOKdcharv:
+            e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar);
+            nextToken();
+            break;
+
+        case TOKstring:
+        case TOKxstring:
+        {
+            // cat adjacent strings
+            utf8_t *s = token.ustring;
+            size_t len = token.len;
+            unsigned char postfix = token.postfix;
+            while (1)
+            {
+                nextToken();
+                if (token.value == TOKstring ||
+                    token.value == TOKxstring)
+                {
+                    if (token.postfix)
+                    {   if (token.postfix != postfix)
+                            error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
+                        postfix = token.postfix;
+                    }
+
+                    size_t len1 = len;
+                    size_t len2 = token.len;
+                    len = len1 + len2;
+                    utf8_t *s2 = (utf8_t *)mem.xmalloc((len + 1) * sizeof(utf8_t));
+                    memcpy(s2, s, len1 * sizeof(utf8_t));
+                    memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(utf8_t));
+                    s = s2;
+                }
+                else
+                    break;
+            }
+            e = new StringExp(loc, s, len, postfix);
+            break;
+        }
+
+        case TOKvoid:    t = Type::tvoid;  goto LabelX;
+        case TOKint8:    t = Type::tint8;  goto LabelX;
+        case TOKuns8:    t = Type::tuns8;  goto LabelX;
+        case TOKint16:   t = Type::tint16; goto LabelX;
+        case TOKuns16:   t = Type::tuns16; goto LabelX;
+        case TOKint32:   t = Type::tint32; goto LabelX;
+        case TOKuns32:   t = Type::tuns32; goto LabelX;
+        case TOKint64:   t = Type::tint64; goto LabelX;
+        case TOKuns64:   t = Type::tuns64; goto LabelX;
+        case TOKint128:  t = Type::tint128; goto LabelX;
+        case TOKuns128:  t = Type::tuns128; goto LabelX;
+        case TOKfloat32: t = Type::tfloat32; goto LabelX;
+        case TOKfloat64: t = Type::tfloat64; goto LabelX;
+        case TOKfloat80: t = Type::tfloat80; goto LabelX;
+        case TOKimaginary32: t = Type::timaginary32; goto LabelX;
+        case TOKimaginary64: t = Type::timaginary64; goto LabelX;
+        case TOKimaginary80: t = Type::timaginary80; goto LabelX;
+        case TOKcomplex32: t = Type::tcomplex32; goto LabelX;
+        case TOKcomplex64: t = Type::tcomplex64; goto LabelX;
+        case TOKcomplex80: t = Type::tcomplex80; goto LabelX;
+        case TOKbool:    t = Type::tbool;    goto LabelX;
+        case TOKchar:    t = Type::tchar;    goto LabelX;
+        case TOKwchar:   t = Type::twchar; goto LabelX;
+        case TOKdchar:   t = Type::tdchar; goto LabelX;
+        LabelX:
+            nextToken();
+            if (token.value == TOKlparen)
+            {
+                e = new TypeExp(loc, t);
+                e = new CallExp(loc, e, parseArguments());
+                break;
+            }
+            check(TOKdot, t->toChars());
+            if (token.value != TOKidentifier)
+            {   error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
+                goto Lerr;
+            }
+            e = typeDotIdExp(loc, t, token.ident);
+            nextToken();
+            break;
+
+        case TOKtypeof:
+        {
+            t = parseTypeof();
+            e = new TypeExp(loc, t);
+            break;
+        }
+
+        case TOKvector:
+        {
+            t = parseVector();
+            e = new TypeExp(loc, t);
+            break;
+        }
+
+        case TOKtypeid:
+        {
+            nextToken();
+            check(TOKlparen, "typeid");
+            RootObject *o;
+            if (isDeclaration(&token, 0, TOKreserved, NULL))
+            {   // argument is a type
+                o = parseType();
+            }
+            else
+            {   // argument is an expression
+                o = parseAssignExp();
+            }
+            check(TOKrparen);
+            e = new TypeidExp(loc, o);
+            break;
+        }
+
+        case TOKtraits:
+        {   /* __traits(identifier, args...)
+             */
+            Identifier *ident;
+            Objects *args = NULL;
+
+            nextToken();
+            check(TOKlparen);
+            if (token.value != TOKidentifier)
+            {   error("__traits(identifier, args...) expected");
+                goto Lerr;
+            }
+            ident = token.ident;
+            nextToken();
+            if (token.value == TOKcomma)
+                args = parseTemplateArgumentList();     // __traits(identifier, args...)
+            else
+                check(TOKrparen);               // __traits(identifier)
+
+            e = new TraitsExp(loc, ident, args);
+            break;
+        }
+
+        case TOKis:
+        {
+            Type *targ;
+            Identifier *ident = NULL;
+            Type *tspec = NULL;
+            TOK tok = TOKreserved;
+            TOK tok2 = TOKreserved;
+            TemplateParameters *tpl = NULL;
+
+            nextToken();
+            if (token.value == TOKlparen)
+            {
+                nextToken();
+                targ = parseType(&ident);
+                if (token.value == TOKcolon || token.value == TOKequal)
+                {
+                    tok = token.value;
+                    nextToken();
+                    if (tok == TOKequal &&
+                        (token.value == TOKstruct ||
+                         token.value == TOKunion ||
+                         token.value == TOKclass ||
+                         token.value == TOKsuper ||
+                         token.value == TOKenum ||
+                         token.value == TOKinterface ||
+                         token.value == TOKargTypes ||
+                         token.value == TOKparameters ||
+                         token.value == TOKconst && peek(&token)->value == TOKrparen ||
+                         token.value == TOKimmutable && peek(&token)->value == TOKrparen ||
+                         token.value == TOKshared && peek(&token)->value == TOKrparen ||
+                         token.value == TOKwild && peek(&token)->value == TOKrparen ||
+                         token.value == TOKfunction ||
+                         token.value == TOKdelegate ||
+                         token.value == TOKreturn ||
+                         token.value == TOKvector && peek(&token)->value == TOKrparen))
+                    {
+                        tok2 = token.value;
+                        nextToken();
+                    }
+                    else
+                    {
+                        tspec = parseType();
+                    }
+                }
+                if (tspec)
+                {
+                    if (token.value == TOKcomma)
+                        tpl = parseTemplateParameterList(1);
+                    else
+                    {
+                        tpl = new TemplateParameters();
+                        check(TOKrparen);
+                    }
+                }
+                else
+                    check(TOKrparen);
+            }
+            else
+            {
+                error("(type identifier : specialization) expected following is");
+                goto Lerr;
+            }
+            e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
+            break;
+        }
+
+        case TOKassert:
+        {   Expression *msg = NULL;
+
+            nextToken();
+            check(TOKlparen, "assert");
+            e = parseAssignExp();
+            if (token.value == TOKcomma)
+            {   nextToken();
+                msg = parseAssignExp();
+            }
+            check(TOKrparen);
+            e = new AssertExp(loc, e, msg);
+            break;
+        }
+
+        case TOKmixin:
+        {
+            nextToken();
+            check(TOKlparen, "mixin");
+            e = parseAssignExp();
+            check(TOKrparen);
+            e = new CompileExp(loc, e);
+            break;
+        }
+
+        case TOKimport:
+        {
+            nextToken();
+            check(TOKlparen, "import");
+            e = parseAssignExp();
+            check(TOKrparen);
+            e = new ImportExp(loc, e);
+            break;
+        }
+
+        case TOKnew:
+            e = parseNewExp(NULL);
+            break;
+
+        case TOKlparen:
+        {
+            Token *tk = peekPastParen(&token);
+            if (skipAttributes(tk, &tk) &&
+                (tk->value == TOKgoesto || tk->value == TOKlcurly))
+            {
+                // (arguments) => expression
+                // (arguments) { statements... }
+                goto case_delegate;
+            }
+
+            // ( expression )
+            nextToken();
+            e = parseExpression();
+            e->parens = 1;
+            check(loc, TOKrparen);
+            break;
+        }
+
+        case TOKlbracket:
+        {   /* Parse array literals and associative array literals:
+             *  [ value, value, value ... ]
+             *  [ key:value, key:value, key:value ... ]
+             */
+            Expressions *values = new Expressions();
+            Expressions *keys = NULL;
+
+            nextToken();
+            while (token.value != TOKrbracket && token.value != TOKeof)
+            {
+                    e = parseAssignExp();
+                    if (token.value == TOKcolon && (keys || values->dim == 0))
+                    {   nextToken();
+                        if (!keys)
+                            keys = new Expressions();
+                        keys->push(e);
+                        e = parseAssignExp();
+                    }
+                    else if (keys)
+                    {   error("'key:value' expected for associative array literal");
+                        delete keys;
+                        keys = NULL;
+                    }
+                    values->push(e);
+                    if (token.value == TOKrbracket)
+                        break;
+                    check(TOKcomma);
+            }
+            check(loc, TOKrbracket);
+
+            if (keys)
+                e = new AssocArrayLiteralExp(loc, keys, values);
+            else
+                e = new ArrayLiteralExp(loc, values);
+            break;
+        }
+
+        case TOKlcurly:
+        case TOKfunction:
+        case TOKdelegate:
+        case_delegate:
+        {
+            Dsymbol *s = parseFunctionLiteral();
+            e = new FuncExp(loc, s);
+            break;
+        }
+
+        default:
+            error("expression expected, not '%s'", token.toChars());
+        Lerr:
+            // Anything for e, as long as it's not NULL
+            e = new IntegerExp(loc, 0, Type::tint32);
+            nextToken();
+            break;
+    }
+    return e;
+}
+
+Expression *Parser::parsePostExp(Expression *e)
+{
+    Loc loc;
+
+    while (1)
+    {
+        loc = token.loc;
+        switch (token.value)
+        {
+            case TOKdot:
+                nextToken();
+                if (token.value == TOKidentifier)
+                {   Identifier *id = token.ident;
+
+                    nextToken();
+                    if (token.value == TOKnot && peekNext() != TOKis && peekNext() != TOKin)
+                    {
+                        Objects *tiargs = parseTemplateArguments();
+                        e = new DotTemplateInstanceExp(loc, e, id, tiargs);
+                    }
+                    else
+                        e = new DotIdExp(loc, e, id);
+                    continue;
+                }
+                else if (token.value == TOKnew)
+                {
+                    e = parseNewExp(e);
+                    continue;
+                }
+                else
+                    error("identifier expected following '.', not '%s'", token.toChars());
+                break;
+
+            case TOKplusplus:
+                e = new PostExp(TOKplusplus, loc, e);
+                break;
+
+            case TOKminusminus:
+                e = new PostExp(TOKminusminus, loc, e);
+                break;
+
+            case TOKlparen:
+                e = new CallExp(loc, e, parseArguments());
+                continue;
+
+            case TOKlbracket:
+            {   // array dereferences:
+                //      array[index]
+                //      array[]
+                //      array[lwr .. upr]
+                Expression *index;
+                Expression *upr;
+                Expressions *arguments = new Expressions();
+
+                inBrackets++;
+                nextToken();
+                while (token.value != TOKrbracket && token.value != TOKeof)
+                {
+                    index = parseAssignExp();
+                    if (token.value == TOKslice)
+                    {
+                        // array[..., lwr..upr, ...]
+                        nextToken();
+                        upr = parseAssignExp();
+                        arguments->push(new IntervalExp(loc, index, upr));
+                    }
+                    else
+                        arguments->push(index);
+                    if (token.value == TOKrbracket)
+                        break;
+                    check(TOKcomma);
+                }
+                check(TOKrbracket);
+                inBrackets--;
+                e = new ArrayExp(loc, e, arguments);
+                continue;
+            }
+
+            default:
+                return e;
+        }
+        nextToken();
+    }
+}
+
+Expression *Parser::parseUnaryExp()
+{
+    Expression *e;
+    Loc loc = token.loc;
+
+    switch (token.value)
+    {
+        case TOKand:
+            nextToken();
+            e = parseUnaryExp();
+            e = new AddrExp(loc, e);
+            break;
+
+        case TOKplusplus:
+            nextToken();
+            e = parseUnaryExp();
+            //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
+            e = new PreExp(TOKpreplusplus, loc, e);
+            break;
+
+        case TOKminusminus:
+            nextToken();
+            e = parseUnaryExp();
+            //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
+            e = new PreExp(TOKpreminusminus, loc, e);
+            break;
+
+        case TOKmul:
+            nextToken();
+            e = parseUnaryExp();
+            e = new PtrExp(loc, e);
+            break;
+
+        case TOKmin:
+            nextToken();
+            e = parseUnaryExp();
+            e = new NegExp(loc, e);
+            break;
+
+        case TOKadd:
+            nextToken();
+            e = parseUnaryExp();
+            e = new UAddExp(loc, e);
+            break;
+
+        case TOKnot:
+            nextToken();
+            e = parseUnaryExp();
+            e = new NotExp(loc, e);
+            break;
+
+        case TOKtilde:
+            nextToken();
+            e = parseUnaryExp();
+            e = new ComExp(loc, e);
+            break;
+
+        case TOKdelete:
+            nextToken();
+            e = parseUnaryExp();
+            e = new DeleteExp(loc, e, false);
+            break;
+
+        case TOKcast:                           // cast(type) expression
+        {
+            nextToken();
+            check(TOKlparen);
+            /* Look for cast(), cast(const), cast(immutable),
+             * cast(shared), cast(shared const), cast(wild), cast(shared wild)
+             */
+            unsigned char m = 0;
+            while (1)
+            {
+                switch (token.value)
+                {
+                    case TOKconst:
+                        if (peekNext() == TOKlparen)
+                            break;              // const as type constructor
+                        m |= MODconst;          // const as storage class
+                        nextToken();
+                        continue;
+
+                    case TOKimmutable:
+                        if (peekNext() == TOKlparen)
+                            break;
+                        m |= MODimmutable;
+                        nextToken();
+                        continue;
+
+                    case TOKshared:
+                        if (peekNext() == TOKlparen)
+                            break;
+                        m |= MODshared;
+                        nextToken();
+                        continue;
+
+                    case TOKwild:
+                        if (peekNext() == TOKlparen)
+                            break;
+                        m |= MODwild;
+                        nextToken();
+                        continue;
+
+                    default:
+                        break;
+                }
+                break;
+            }
+            if (token.value == TOKrparen)
+            {
+                nextToken();
+                e = parseUnaryExp();
+                e = new CastExp(loc, e, m);
+            }
+            else
+            {
+                Type *t = parseType();  // cast( type )
+                t = t->addMod(m);       // cast( const type )
+                check(TOKrparen);
+                e = parseUnaryExp();
+                e = new CastExp(loc, e, t);
+            }
+            break;
+        }
+
+        case TOKwild:
+        case TOKshared:
+        case TOKconst:
+        case TOKimmutable:      // immutable(type)(arguments) / immutable(type).init
+        {
+            StorageClass stc = parseTypeCtor();
+            Type *t = parseBasicType();
+            t = t->addSTC(stc);
+            e = new TypeExp(loc, t);
+            if (stc == 0 && token.value == TOKdot)
+            {
+                nextToken();
+                if (token.value != TOKidentifier)
+                {
+                    error("identifier expected following (type).");
+                    return NULL;
+                }
+                e = typeDotIdExp(loc, t, token.ident);
+                nextToken();
+                e = parsePostExp(e);
+                break;
+            }
+            else if (token.value != TOKlparen)
+            {
+                error("(arguments) expected following %s", t->toChars());
+                return e;
+            }
+            e = new CallExp(loc, e, parseArguments());
+            break;
+        }
+
+
+        case TOKlparen:
+        {   Token *tk;
+
+            tk = peek(&token);
+#if CCASTSYNTAX
+            // If cast
+            if (isDeclaration(tk, 0, TOKrparen, &tk))
+            {
+                tk = peek(tk);          // skip over right parenthesis
+                switch (tk->value)
+                {
+                    case TOKnot:
+                        tk = peek(tk);
+                        if (tk->value == TOKis || tk->value == TOKin)   // !is or !in
+                            break;
+                    case TOKdot:
+                    case TOKplusplus:
+                    case TOKminusminus:
+                    case TOKdelete:
+                    case TOKnew:
+                    case TOKlparen:
+                    case TOKidentifier:
+                    case TOKthis:
+                    case TOKsuper:
+                    case TOKint32v:
+                    case TOKuns32v:
+                    case TOKint64v:
+                    case TOKuns64v:
+                    case TOKint128v:
+                    case TOKuns128v:
+                    case TOKfloat32v:
+                    case TOKfloat64v:
+                    case TOKfloat80v:
+                    case TOKimaginary32v:
+                    case TOKimaginary64v:
+                    case TOKimaginary80v:
+                    case TOKnull:
+                    case TOKtrue:
+                    case TOKfalse:
+                    case TOKcharv:
+                    case TOKwcharv:
+                    case TOKdcharv:
+                    case TOKstring:
+#if 0
+                    case TOKtilde:
+                    case TOKand:
+                    case TOKmul:
+                    case TOKmin:
+                    case TOKadd:
+#endif
+                    case TOKfunction:
+                    case TOKdelegate:
+                    case TOKtypeof:
+                    case TOKvector:
+                    case TOKfile:
+                    case TOKfilefullpath:
+                    case TOKline:
+                    case TOKmodulestring:
+                    case TOKfuncstring:
+                    case TOKprettyfunc:
+                    case TOKwchar: case TOKdchar:
+                    case TOKbool: case TOKchar:
+                    case TOKint8: case TOKuns8:
+                    case TOKint16: case TOKuns16:
+                    case TOKint32: case TOKuns32:
+                    case TOKint64: case TOKuns64:
+                    case TOKint128: case TOKuns128:
+                    case TOKfloat32: case TOKfloat64: case TOKfloat80:
+                    case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+                    case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+                    case TOKvoid:
+                    {   // (type) una_exp
+                        Type *t;
+
+                        nextToken();
+                        t = parseType();
+                        check(TOKrparen);
+
+                        // if .identifier
+                        // or .identifier!( ... )
+                        if (token.value == TOKdot)
+                        {
+                            if (peekNext() != TOKidentifier &&  peekNext() != TOKnew)
+                            {
+                                error("identifier or new keyword expected following (...).");
+                                return NULL;
+                            }
+                            e = new TypeExp(loc, t);
+                            e = parsePostExp(e);
+                        }
+                        else
+                        {
+                            e = parseUnaryExp();
+                            e = new CastExp(loc, e, t);
+                            error("C style cast illegal, use %s", e->toChars());
+                        }
+                        return e;
+                    }
+                    default:
+                        break;
+                }
+            }
+#endif
+            e = parsePrimaryExp();
+            e = parsePostExp(e);
+            break;
+        }
+        default:
+            e = parsePrimaryExp();
+            e = parsePostExp(e);
+            break;
+    }
+    assert(e);
+
+    // ^^ is right associative and has higher precedence than the unary operators
+    while (token.value == TOKpow)
+    {
+        nextToken();
+        Expression *e2 = parseUnaryExp();
+        e = new PowExp(loc, e, e2);
+    }
+
+    return e;
+}
+
+Expression *Parser::parseMulExp()
+{
+    Expression *e;
+    Expression *e2;
+    Loc loc = token.loc;
+
+    e = parseUnaryExp();
+    while (1)
+    {
+        switch (token.value)
+        {
+            case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
+            case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
+            case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
+
+            default:
+                break;
+        }
+        break;
+    }
+    return e;
+}
+
+Expression *Parser::parseAddExp()
+{
+    Expression *e;
+    Expression *e2;
+    Loc loc = token.loc;
+
+    e = parseMulExp();
+    while (1)
+    {
+        switch (token.value)
+        {
+            case TOKadd:    nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
+            case TOKmin:    nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
+            case TOKtilde:  nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
+
+            default:
+                break;
+        }
+        break;
+    }
+    return e;
+}
+
+Expression *Parser::parseShiftExp()
+{
+    Expression *e;
+    Expression *e2;
+    Loc loc = token.loc;
+
+    e = parseAddExp();
+    while (1)
+    {
+        switch (token.value)
+        {
+            case TOKshl:  nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2);  continue;
+            case TOKshr:  nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2);  continue;
+            case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
+
+            default:
+                break;
+        }
+        break;
+    }
+    return e;
+}
+
+Expression *Parser::parseCmpExp()
+{
+    Expression *e;
+    Expression *e2;
+    Token *t;
+    Loc loc = token.loc;
+
+    e = parseShiftExp();
+    TOK op = token.value;
+
+    switch (op)
+    {
+        case TOKequal:
+        case TOKnotequal:
+            nextToken();
+            e2 = parseShiftExp();
+            e = new EqualExp(op, loc, e, e2);
+            break;
+
+        case TOKis:
+            op = TOKidentity;
+            goto L1;
+
+        case TOKnot:
+            // Attempt to identify '!is'
+            t = peek(&token);
+            if (t->value == TOKin)
+            {
+                nextToken();
+                nextToken();
+                e2 = parseShiftExp();
+                e = new InExp(loc, e, e2);
+                e = new NotExp(loc, e);
+                break;
+            }
+            if (t->value != TOKis)
+                break;
+            nextToken();
+            op = TOKnotidentity;
+            goto L1;
+
+        L1:
+            nextToken();
+            e2 = parseShiftExp();
+            e = new IdentityExp(op, loc, e, e2);
+            break;
+
+        case TOKlt:
+        case TOKle:
+        case TOKgt:
+        case TOKge:
+        case TOKunord:
+        case TOKlg:
+        case TOKleg:
+        case TOKule:
+        case TOKul:
+        case TOKuge:
+        case TOKug:
+        case TOKue:
+            nextToken();
+            e2 = parseShiftExp();
+            e = new CmpExp(op, loc, e, e2);
+            break;
+
+        case TOKin:
+            nextToken();
+            e2 = parseShiftExp();
+            e = new InExp(loc, e, e2);
+            break;
+
+        default:
+            break;
+    }
+    return e;
+}
+
+Expression *Parser::parseAndExp()
+{
+    Loc loc = token.loc;
+
+    Expression *e = parseCmpExp();
+    while (token.value == TOKand)
+    {
+        checkParens(TOKand, e);
+        nextToken();
+        Expression *e2 = parseCmpExp();
+        checkParens(TOKand, e2);
+        e = new AndExp(loc,e,e2);
+        loc = token.loc;
+    }
+    return e;
+}
+
+Expression *Parser::parseXorExp()
+{
+    Loc loc = token.loc;
+
+    Expression *e = parseAndExp();
+    while (token.value == TOKxor)
+    {
+        checkParens(TOKxor, e);
+        nextToken();
+        Expression *e2 = parseAndExp();
+        checkParens(TOKxor, e2);
+        e = new XorExp(loc, e, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseOrExp()
+{
+    Loc loc = token.loc;
+
+    Expression *e = parseXorExp();
+    while (token.value == TOKor)
+    {
+        checkParens(TOKor, e);
+        nextToken();
+        Expression *e2 = parseXorExp();
+        checkParens(TOKor, e2);
+        e = new OrExp(loc, e, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseAndAndExp()
+{
+    Expression *e;
+    Expression *e2;
+    Loc loc = token.loc;
+
+    e = parseOrExp();
+    while (token.value == TOKandand)
+    {
+        nextToken();
+        e2 = parseOrExp();
+        e = new AndAndExp(loc, e, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseOrOrExp()
+{
+    Expression *e;
+    Expression *e2;
+    Loc loc = token.loc;
+
+    e = parseAndAndExp();
+    while (token.value == TOKoror)
+    {
+        nextToken();
+        e2 = parseAndAndExp();
+        e = new OrOrExp(loc, e, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseCondExp()
+{
+    Expression *e;
+    Expression *e1;
+    Expression *e2;
+    Loc loc = token.loc;
+
+    e = parseOrOrExp();
+    if (token.value == TOKquestion)
+    {
+        nextToken();
+        e1 = parseExpression();
+        check(TOKcolon);
+        e2 = parseCondExp();
+        e = new CondExp(loc, e, e1, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseAssignExp()
+{
+    Expression *e;
+    Expression *e2;
+    Loc loc;
+
+    e = parseCondExp();
+    while (1)
+    {
+        loc = token.loc;
+        switch (token.value)
+        {
+            case TOKassign:   nextToken(); e2 = parseAssignExp(); e = new AssignExp(loc,e,e2); continue;
+            case TOKaddass:   nextToken(); e2 = parseAssignExp(); e = new AddAssignExp(loc,e,e2); continue;
+            case TOKminass:   nextToken(); e2 = parseAssignExp(); e = new MinAssignExp(loc,e,e2); continue;
+            case TOKmulass:   nextToken(); e2 = parseAssignExp(); e = new MulAssignExp(loc,e,e2); continue;
+            case TOKdivass:   nextToken(); e2 = parseAssignExp(); e = new DivAssignExp(loc,e,e2); continue;
+            case TOKmodass:   nextToken(); e2 = parseAssignExp(); e = new ModAssignExp(loc,e,e2); continue;
+            case TOKpowass:   nextToken(); e2 = parseAssignExp(); e = new PowAssignExp(loc,e,e2); continue;
+            case TOKandass:   nextToken(); e2 = parseAssignExp(); e = new AndAssignExp(loc,e,e2); continue;
+            case TOKorass:    nextToken(); e2 = parseAssignExp(); e = new OrAssignExp(loc,e,e2); continue;
+            case TOKxorass:   nextToken(); e2 = parseAssignExp(); e = new XorAssignExp(loc,e,e2); continue;
+            case TOKshlass:   nextToken(); e2 = parseAssignExp(); e = new ShlAssignExp(loc,e,e2); continue;
+            case TOKshrass:   nextToken(); e2 = parseAssignExp(); e = new ShrAssignExp(loc,e,e2); continue;
+            case TOKushrass:  nextToken(); e2 = parseAssignExp(); e = new UshrAssignExp(loc,e,e2); continue;
+            case TOKcatass:   nextToken(); e2 = parseAssignExp(); e = new CatAssignExp(loc,e,e2); continue;
+            default:
+                break;
+        }
+        break;
+    }
+    return e;
+}
+
+Expression *Parser::parseExpression()
+{
+    Expression *e;
+    Expression *e2;
+    Loc loc = token.loc;
+
+    //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
+    e = parseAssignExp();
+    while (token.value == TOKcomma)
+    {
+        nextToken();
+        e2 = parseAssignExp();
+        e = new CommaExp(loc, e, e2, false);
+        loc = token.loc;
+    }
+    return e;
+}
+
+
+/*************************
+ * Collect argument list.
+ * Assume current token is ',', '(' or '['.
+ */
+
+Expressions *Parser::parseArguments()
+{   // function call
+    Expressions *arguments;
+    Expression *arg;
+    TOK endtok;
+
+    arguments = new Expressions();
+    if (token.value == TOKlbracket)
+        endtok = TOKrbracket;
+    else
+        endtok = TOKrparen;
+
+    {
+        nextToken();
+        while (token.value != endtok && token.value != TOKeof)
+        {
+                arg = parseAssignExp();
+                arguments->push(arg);
+                if (token.value == endtok)
+                    break;
+                check(TOKcomma);
+        }
+        check(endtok);
+    }
+    return arguments;
+}
+
+/*******************************************
+ */
+
+Expression *Parser::parseNewExp(Expression *thisexp)
+{
+    Type *t;
+    Expressions *newargs;
+    Expressions *arguments = NULL;
+    Loc loc = token.loc;
+
+    nextToken();
+    newargs = NULL;
+    if (token.value == TOKlparen)
+    {
+        newargs = parseArguments();
+    }
+
+    // An anonymous nested class starts with "class"
+    if (token.value == TOKclass)
+    {
+        nextToken();
+        if (token.value == TOKlparen)
+            arguments = parseArguments();
+
+        BaseClasses *baseclasses = NULL;
+        if (token.value != TOKlcurly)
+            baseclasses = parseBaseClasses();
+
+        Identifier *id = NULL;
+        Dsymbols *members = NULL;
+
+        if (token.value != TOKlcurly)
+        {
+            error("{ members } expected for anonymous class");
+        }
+        else
+        {
+            nextToken();
+            members = parseDeclDefs(0);
+            if (token.value != TOKrcurly)
+                error("class member expected");
+            nextToken();
+        }
+
+        ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses, members, false);
+        Expression *e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
+
+        return e;
+    }
+
+    StorageClass stc = parseTypeCtor();
+    t = parseBasicType(true);
+    t = parseBasicType2(t);
+    t = t->addSTC(stc);
+    if (t->ty == Taarray)
+    {   TypeAArray *taa = (TypeAArray *)t;
+        Type *index = taa->index;
+
+        Expression *e = typeToExpression(index);
+        if (e)
+        {   arguments = new Expressions();
+            arguments->push(e);
+            t = new TypeDArray(taa->next);
+        }
+        else
+        {
+            error("need size of rightmost array, not type %s", index->toChars());
+            return new NullExp(loc);
+        }
+    }
+    else if (t->ty == Tsarray)
+    {
+        TypeSArray *tsa = (TypeSArray *)t;
+        Expression *e = tsa->dim;
+
+        arguments = new Expressions();
+        arguments->push(e);
+        t = new TypeDArray(tsa->next);
+    }
+    else if (token.value == TOKlparen)
+    {
+        arguments = parseArguments();
+    }
+    Expression *e = new NewExp(loc, thisexp, newargs, t, arguments);
+    return e;
+}
+
+/**********************************************
+ */
+
+void Parser::addComment(Dsymbol *s, const utf8_t *blockComment)
+{
+    s->addComment(combineComments(blockComment, token.lineComment));
+    token.lineComment = NULL;
+}
+
+
+/**********************************
+ * Set operator precedence for each operator.
+ */
+
+PREC precedence[TOKMAX];
+
+struct PrecedenceInitializer
+{
+    PrecedenceInitializer();
+};
+
+static PrecedenceInitializer precedenceinitializer;
+
+PrecedenceInitializer::PrecedenceInitializer()
+{
+    for (size_t i = 0; i < TOKMAX; i++)
+        precedence[i] = PREC_zero;
+
+    precedence[TOKtype] = PREC_expr;
+    precedence[TOKerror] = PREC_expr;
+
+    precedence[TOKtypeof] = PREC_primary;
+    precedence[TOKmixin] = PREC_primary;
+    precedence[TOKimport] = PREC_primary;
+
+    precedence[TOKdotvar] = PREC_primary;
+    precedence[TOKscope] = PREC_primary;
+    precedence[TOKidentifier] = PREC_primary;
+    precedence[TOKthis] = PREC_primary;
+    precedence[TOKsuper] = PREC_primary;
+    precedence[TOKint64] = PREC_primary;
+    precedence[TOKfloat64] = PREC_primary;
+    precedence[TOKcomplex80] = PREC_primary;
+    precedence[TOKnull] = PREC_primary;
+    precedence[TOKstring] = PREC_primary;
+    precedence[TOKarrayliteral] = PREC_primary;
+    precedence[TOKassocarrayliteral] = PREC_primary;
+    precedence[TOKclassreference] = PREC_primary;
+    precedence[TOKfile] = PREC_primary;
+    precedence[TOKfilefullpath] = PREC_primary;
+    precedence[TOKline] = PREC_primary;
+    precedence[TOKmodulestring] = PREC_primary;
+    precedence[TOKfuncstring] = PREC_primary;
+    precedence[TOKprettyfunc] = PREC_primary;
+    precedence[TOKtypeid] = PREC_primary;
+    precedence[TOKis] = PREC_primary;
+    precedence[TOKassert] = PREC_primary;
+    precedence[TOKhalt] = PREC_primary;
+    precedence[TOKtemplate] = PREC_primary;
+    precedence[TOKdsymbol] = PREC_primary;
+    precedence[TOKfunction] = PREC_primary;
+    precedence[TOKvar] = PREC_primary;
+    precedence[TOKsymoff] = PREC_primary;
+    precedence[TOKstructliteral] = PREC_primary;
+    precedence[TOKarraylength] = PREC_primary;
+    precedence[TOKdelegateptr] = PREC_primary;
+    precedence[TOKdelegatefuncptr] = PREC_primary;
+    precedence[TOKremove] = PREC_primary;
+    precedence[TOKtuple] = PREC_primary;
+    precedence[TOKtraits] = PREC_primary;
+    precedence[TOKdefault] = PREC_primary;
+    precedence[TOKoverloadset] = PREC_primary;
+    precedence[TOKvoid] = PREC_primary;
+
+    // post
+    precedence[TOKdotti] = PREC_primary;
+    precedence[TOKdotid] = PREC_primary;
+    precedence[TOKdottd] = PREC_primary;
+    precedence[TOKdot] = PREC_primary;
+    precedence[TOKdottype] = PREC_primary;
+//  precedence[TOKarrow] = PREC_primary;
+    precedence[TOKplusplus] = PREC_primary;
+    precedence[TOKminusminus] = PREC_primary;
+    precedence[TOKpreplusplus] = PREC_primary;
+    precedence[TOKpreminusminus] = PREC_primary;
+    precedence[TOKcall] = PREC_primary;
+    precedence[TOKslice] = PREC_primary;
+    precedence[TOKarray] = PREC_primary;
+    precedence[TOKindex] = PREC_primary;
+
+    precedence[TOKdelegate] = PREC_unary;
+    precedence[TOKaddress] = PREC_unary;
+    precedence[TOKstar] = PREC_unary;
+    precedence[TOKneg] = PREC_unary;
+    precedence[TOKuadd] = PREC_unary;
+    precedence[TOKnot] = PREC_unary;
+    precedence[TOKtilde] = PREC_unary;
+    precedence[TOKdelete] = PREC_unary;
+    precedence[TOKnew] = PREC_unary;
+    precedence[TOKnewanonclass] = PREC_unary;
+    precedence[TOKcast] = PREC_unary;
+
+    precedence[TOKvector] = PREC_unary;
+    precedence[TOKpow] = PREC_pow;
+
+    precedence[TOKmul] = PREC_mul;
+    precedence[TOKdiv] = PREC_mul;
+    precedence[TOKmod] = PREC_mul;
+
+    precedence[TOKadd] = PREC_add;
+    precedence[TOKmin] = PREC_add;
+    precedence[TOKcat] = PREC_add;
+
+    precedence[TOKshl] = PREC_shift;
+    precedence[TOKshr] = PREC_shift;
+    precedence[TOKushr] = PREC_shift;
+
+    precedence[TOKlt] = PREC_rel;
+    precedence[TOKle] = PREC_rel;
+    precedence[TOKgt] = PREC_rel;
+    precedence[TOKge] = PREC_rel;
+    precedence[TOKunord] = PREC_rel;
+    precedence[TOKlg] = PREC_rel;
+    precedence[TOKleg] = PREC_rel;
+    precedence[TOKule] = PREC_rel;
+    precedence[TOKul] = PREC_rel;
+    precedence[TOKuge] = PREC_rel;
+    precedence[TOKug] = PREC_rel;
+    precedence[TOKue] = PREC_rel;
+    precedence[TOKin] = PREC_rel;
+
+#if 0
+    precedence[TOKequal] = PREC_equal;
+    precedence[TOKnotequal] = PREC_equal;
+    precedence[TOKidentity] = PREC_equal;
+    precedence[TOKnotidentity] = PREC_equal;
+#else
+    /* Note that we changed precedence, so that < and != have the same
+     * precedence. This change is in the parser, too.
+     */
+    precedence[TOKequal] = PREC_rel;
+    precedence[TOKnotequal] = PREC_rel;
+    precedence[TOKidentity] = PREC_rel;
+    precedence[TOKnotidentity] = PREC_rel;
+#endif
+
+    precedence[TOKand] = PREC_and;
+
+    precedence[TOKxor] = PREC_xor;
+
+    precedence[TOKor] = PREC_or;
+
+    precedence[TOKandand] = PREC_andand;
+
+    precedence[TOKoror] = PREC_oror;
+
+    precedence[TOKquestion] = PREC_cond;
+
+    precedence[TOKassign] = PREC_assign;
+    precedence[TOKconstruct] = PREC_assign;
+    precedence[TOKblit] = PREC_assign;
+    precedence[TOKaddass] = PREC_assign;
+    precedence[TOKminass] = PREC_assign;
+    precedence[TOKcatass] = PREC_assign;
+    precedence[TOKmulass] = PREC_assign;
+    precedence[TOKdivass] = PREC_assign;
+    precedence[TOKmodass] = PREC_assign;
+    precedence[TOKpowass] = PREC_assign;
+    precedence[TOKshlass] = PREC_assign;
+    precedence[TOKshrass] = PREC_assign;
+    precedence[TOKushrass] = PREC_assign;
+    precedence[TOKandass] = PREC_assign;
+    precedence[TOKorass] = PREC_assign;
+    precedence[TOKxorass] = PREC_assign;
+
+    precedence[TOKcomma] = PREC_expr;
+    precedence[TOKdeclaration] = PREC_expr;
+
+    precedence[TOKinterval] = PREC_assign;
+}
diff --git a/gcc/d/dfrontend/parse.h b/gcc/d/dfrontend/parse.h
new file mode 100644
index 00000000000..b589e628f2b
--- /dev/null
+++ b/gcc/d/dfrontend/parse.h
@@ -0,0 +1,202 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/parse.h
+ */
+
+#ifndef DMD_PARSE_H
+#define DMD_PARSE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "arraytypes.h"
+#include "lexer.h"
+#include "enum.h"
+
+class Type;
+class TypeQualified;
+class Expression;
+class Declaration;
+class Statement;
+class Import;
+class Initializer;
+class FuncDeclaration;
+class CtorDeclaration;
+class PostBlitDeclaration;
+class DtorDeclaration;
+class StaticCtorDeclaration;
+class StaticDtorDeclaration;
+class SharedStaticCtorDeclaration;
+class SharedStaticDtorDeclaration;
+class ConditionalDeclaration;
+class InvariantDeclaration;
+class UnitTestDeclaration;
+class NewDeclaration;
+class DeleteDeclaration;
+class Condition;
+class Module;
+struct ModuleDeclaration;
+class TemplateDeclaration;
+class TemplateInstance;
+class StaticAssert;
+struct PrefixAttributes;
+
+/************************************
+ * These control how parseStatement() works.
+ */
+
+enum ParseStatementFlags
+{
+    PSsemi = 1,         // empty ';' statements are allowed, but deprecated
+    PSscope = 2,        // start a new scope
+    PScurly = 4,        // { } statement is required
+    PScurlyscope = 8,   // { } starts a new scope
+    PSsemi_ok = 0x10,   // empty ';' are really ok
+};
+
+
+class Parser : public Lexer
+{
+public:
+    Module *mod;
+    ModuleDeclaration *md;
+    LINK linkage;
+    CPPMANGLE cppmangle;
+    Loc endloc;                 // set to location of last right curly
+    int inBrackets;             // inside [] of array index or slice
+    Loc lookingForElse;         // location of lonely if looking for an else
+
+    Parser(Loc loc, Module *module, const utf8_t *base, size_t length, bool doDocComment);
+    Parser(Module *module, const utf8_t *base, size_t length, bool doDocComment);
+
+    Dsymbols *parseModule();
+    Dsymbols *parseDeclDefs(int once, Dsymbol **pLastDecl = NULL, PrefixAttributes *pAttrs = NULL);
+    Dsymbols *parseAutoDeclarations(StorageClass storageClass, const utf8_t *comment);
+    Dsymbols *parseBlock(Dsymbol **pLastDecl, PrefixAttributes *pAttrs = NULL);
+    StorageClass appendStorageClass(StorageClass storageClass, StorageClass stc, bool deprec = false);
+    StorageClass parseAttribute(Expressions **pexps);
+    StorageClass parsePostfix(StorageClass storageClass, Expressions **pudas);
+    StorageClass parseTypeCtor();
+    Expression *parseConstraint();
+    TemplateDeclaration *parseTemplateDeclaration(bool ismixin = false);
+    TemplateParameters *parseTemplateParameterList(int flag = 0);
+    Dsymbol *parseMixin();
+    Objects *parseTemplateArguments();
+    Objects *parseTemplateArgumentList();
+    Objects *parseTemplateSingleArgument();
+    StaticAssert *parseStaticAssert();
+    TypeQualified *parseTypeof();
+    Type *parseVector();
+    LINK parseLinkage(Identifiers **, CPPMANGLE *);
+    Identifiers *parseQualifiedIdentifier(const char *entity);
+    Condition *parseDebugCondition();
+    Condition *parseVersionCondition();
+    Condition *parseStaticIfCondition();
+    Dsymbol *parseCtor(PrefixAttributes *pAttrs);
+    Dsymbol *parseDtor(PrefixAttributes *pAttrs);
+    Dsymbol *parseStaticCtor(PrefixAttributes *pAttrs);
+    Dsymbol *parseStaticDtor(PrefixAttributes *pAttrs);
+    Dsymbol *parseSharedStaticCtor(PrefixAttributes *pAttrs);
+    Dsymbol *parseSharedStaticDtor(PrefixAttributes *pAttrs);
+    Dsymbol *parseInvariant(PrefixAttributes *pAttrs);
+    Dsymbol *parseUnitTest(PrefixAttributes *pAttrs);
+    Dsymbol *parseNew(PrefixAttributes *pAttrs);
+    Dsymbol *parseDelete(PrefixAttributes *pAttrs);
+    Parameters *parseParameters(int *pvarargs, TemplateParameters **tpl = NULL);
+    EnumDeclaration *parseEnum();
+    Dsymbol *parseAggregate();
+    BaseClasses *parseBaseClasses();
+    Dsymbols *parseImport();
+    Type *parseType(Identifier **pident = NULL, TemplateParameters **ptpl = NULL);
+    Type *parseBasicType(bool dontLookDotIdents = false);
+    Type *parseBasicTypeStartingAt(TypeQualified *tid, bool dontLookDotIdents);
+    Type *parseBasicType2(Type *t);
+    Type *parseDeclarator(Type *t, int *alt, Identifier **pident,
+        TemplateParameters **tpl = NULL, StorageClass storage_class = 0, int *pdisable = NULL, Expressions **pudas = NULL);
+    void parseStorageClasses(StorageClass &storage_class, LINK &link, bool &setAlignment, Expression *&ealign, Expressions *&udas);
+    Dsymbols *parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, const utf8_t *comment);
+    Dsymbol *parseFunctionLiteral();
+    FuncDeclaration *parseContracts(FuncDeclaration *f);
+    void checkDanglingElse(Loc elseloc);
+    void checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident);
+    /** endPtr used for documented unittests */
+    Statement *parseStatement(int flags, const utf8_t** endPtr = NULL, Loc *pEndloc = NULL);
+#ifdef IN_GCC
+    Statement *parseExtAsm(StorageClass stc);
+    int parseExtAsmOperands(Expressions *args, Identifiers *names, Expressions *constraints);
+    Expressions *parseExtAsmClobbers();
+    Identifiers *parseExtAsmGotoLabels();
+#endif
+    Initializer *parseInitializer();
+    Expression *parseDefaultInitExp();
+    void check(Loc loc, TOK value);
+    void check(TOK value);
+    void check(TOK value, const char *string);
+    void checkParens(TOK value, Expression *e);
+    bool isDeclaration(Token *t, int needId, TOK endtok, Token **pt);
+    bool isBasicType(Token **pt);
+    bool isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok);
+    bool isParameters(Token **pt);
+    bool isExpression(Token **pt);
+    bool skipParens(Token *t, Token **pt);
+    bool skipParensIf(Token *t, Token **pt);
+    bool skipAttributes(Token *t, Token **pt);
+
+    Expression *parseExpression();
+    Expression *parsePrimaryExp();
+    Expression *parseUnaryExp();
+    Expression *parsePostExp(Expression *e);
+    Expression *parseMulExp();
+    Expression *parseAddExp();
+    Expression *parseShiftExp();
+    Expression *parseCmpExp();
+    Expression *parseAndExp();
+    Expression *parseXorExp();
+    Expression *parseOrExp();
+    Expression *parseAndAndExp();
+    Expression *parseOrOrExp();
+    Expression *parseCondExp();
+    Expression *parseAssignExp();
+
+    Expressions *parseArguments();
+
+    Expression *parseNewExp(Expression *thisexp);
+
+    void addComment(Dsymbol *s, const utf8_t *blockComment);
+};
+
+// Operator precedence - greater values are higher precedence
+
+enum PREC
+{
+    PREC_zero,
+    PREC_expr,
+    PREC_assign,
+    PREC_cond,
+    PREC_oror,
+    PREC_andand,
+    PREC_or,
+    PREC_xor,
+    PREC_and,
+    PREC_equal,
+    PREC_rel,
+    PREC_shift,
+    PREC_add,
+    PREC_mul,
+    PREC_pow,
+    PREC_unary,
+    PREC_primary,
+};
+
+extern PREC precedence[TOKMAX];
+
+void initPrecedence();
+
+#endif /* DMD_PARSE_H */
diff --git a/gcc/d/dfrontend/port.h b/gcc/d/dfrontend/port.h
new file mode 100644
index 00000000000..dacd9eff636
--- /dev/null
+++ b/gcc/d/dfrontend/port.h
@@ -0,0 +1,47 @@
+
+/* Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/dlang/dmd/blob/master/src/root/port.h
+ */
+
+#ifndef PORT_H
+#define PORT_H
+
+// Portable wrapper around compiler/system specific things.
+// The idea is to minimize #ifdef's in the app code.
+
+#include <stdlib.h> // for alloca
+#include <stdint.h>
+
+#if _MSC_VER
+#include <alloca.h>
+typedef __int64 longlong;
+typedef unsigned __int64 ulonglong;
+#else
+typedef long long longlong;
+typedef unsigned long long ulonglong;
+#endif
+
+typedef unsigned char utf8_t;
+
+struct Port
+{
+    static int memicmp(const char *s1, const char *s2, size_t n);
+    static char *strupr(char *s);
+
+    static bool isFloat32LiteralOutOfRange(const char *s);
+    static bool isFloat64LiteralOutOfRange(const char *s);
+
+    static void writelongLE(unsigned value, void *buffer);
+    static unsigned readlongLE(void *buffer);
+    static void writelongBE(unsigned value, void *buffer);
+    static unsigned readlongBE(void *buffer);
+    static unsigned readwordLE(void *buffer);
+    static unsigned readwordBE(void *buffer);
+    static void valcpy(void *dst, uint64_t val, size_t size);
+};
+
+#endif
diff --git a/gcc/d/dfrontend/readme.txt b/gcc/d/dfrontend/readme.txt
new file mode 100644
index 00000000000..a9a31af1b6e
--- /dev/null
+++ b/gcc/d/dfrontend/readme.txt
@@ -0,0 +1,13 @@
+This is the source code to the DMD compiler
+for the D Programming Language defined in the documents at
+http://dlang.org/
+
+These sources are free, they are redistributable and modifiable
+under the terms of the Boost Software License, Version 1.0.
+The terms of this license are in the file boostlicense.txt,
+or see http://www.boost.org/LICENSE_1_0.txt.
+
+If a particular file has a different license in it, that overrides
+this license for that file.
+
+-Walter Bright
diff --git a/gcc/d/dfrontend/rmem.c b/gcc/d/dfrontend/rmem.c
new file mode 100644
index 00000000000..568df89548e
--- /dev/null
+++ b/gcc/d/dfrontend/rmem.c
@@ -0,0 +1,163 @@
+
+/* Copyright (c) 2000-2014 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/rmem.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rmem.h"
+
+/* This implementation of the storage allocator uses the standard C allocation package.
+ */
+
+Mem mem;
+
+char *Mem::xstrdup(const char *s)
+{
+    char *p;
+
+    if (s)
+    {
+        p = strdup(s);
+        if (p)
+            return p;
+        error();
+    }
+    return NULL;
+}
+
+void *Mem::xmalloc(size_t size)
+{   void *p;
+
+    if (!size)
+        p = NULL;
+    else
+    {
+        p = malloc(size);
+        if (!p)
+            error();
+    }
+    return p;
+}
+
+void *Mem::xcalloc(size_t size, size_t n)
+{   void *p;
+
+    if (!size || !n)
+        p = NULL;
+    else
+    {
+        p = calloc(size, n);
+        if (!p)
+            error();
+    }
+    return p;
+}
+
+void *Mem::xrealloc(void *p, size_t size)
+{
+    if (!size)
+    {   if (p)
+        {
+            free(p);
+            p = NULL;
+        }
+    }
+    else if (!p)
+    {
+        p = malloc(size);
+        if (!p)
+            error();
+    }
+    else
+    {
+        void *psave = p;
+        p = realloc(psave, size);
+        if (!p)
+        {   xfree(psave);
+            error();
+        }
+    }
+    return p;
+}
+
+void Mem::xfree(void *p)
+{
+    if (p)
+        free(p);
+}
+
+void *Mem::xmallocdup(void *o, size_t size)
+{   void *p;
+
+    if (!size)
+        p = NULL;
+    else
+    {
+        p = malloc(size);
+        if (!p)
+            error();
+        else
+            memcpy(p,o,size);
+    }
+    return p;
+}
+
+void Mem::error()
+{
+    printf("Error: out of memory\n");
+    exit(EXIT_FAILURE);
+}
+
+/* =================================================== */
+
+/* Allocate, but never release
+ */
+
+// Allocate a little less than 1Mb because the C runtime adds some overhead that
+// causes the actual memory block to be larger than 1Mb otherwise.
+#define CHUNK_SIZE (256 * 4096 - 64)
+
+static size_t heapleft = 0;
+static void *heapp;
+
+extern "C" void *allocmemory(size_t m_size)
+{
+    // 16 byte alignment is better (and sometimes needed) for doubles
+    m_size = (m_size + 15) & ~15;
+
+    // The layout of the code is selected so the most common case is straight through
+    if (m_size <= heapleft)
+    {
+     L1:
+        heapleft -= m_size;
+        void *p = heapp;
+        heapp = (void *)((char *)heapp + m_size);
+        return p;
+    }
+
+    if (m_size > CHUNK_SIZE)
+    {
+        void *p = malloc(m_size);
+        if (p)
+            return p;
+        printf("Error: out of memory\n");
+        exit(EXIT_FAILURE);
+        return p;
+    }
+
+    heapleft = CHUNK_SIZE;
+    heapp = malloc(CHUNK_SIZE);
+    if (!heapp)
+    {
+        printf("Error: out of memory\n");
+        exit(EXIT_FAILURE);
+    }
+    goto L1;
+}
diff --git a/gcc/d/dfrontend/rmem.h b/gcc/d/dfrontend/rmem.h
new file mode 100644
index 00000000000..1c8d4ac7856
--- /dev/null
+++ b/gcc/d/dfrontend/rmem.h
@@ -0,0 +1,39 @@
+/**
+ * Compiler implementation of the
+ * $(LINK2 http://www.dlang.org, D programming language).
+ *
+ * Copyright:   Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved
+ * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ */
+
+#ifndef ROOT_MEM_H
+#define ROOT_MEM_H
+
+#include <stddef.h>     // for size_t
+
+#if __APPLE__ && __i386__
+    /* size_t is 'unsigned long', which makes it mangle differently
+     * than D's 'uint'
+     */
+    typedef unsigned d_size_t;
+#else
+    typedef size_t d_size_t;
+#endif
+
+struct Mem
+{
+    Mem() { }
+
+    static char *xstrdup(const char *s);
+    static void *xmalloc(d_size_t size);
+    static void *xcalloc(d_size_t size, d_size_t n);
+    static void *xrealloc(void *p, d_size_t size);
+    static void xfree(void *p);
+    static void *xmallocdup(void *o, d_size_t size);
+    static void error();
+};
+
+extern Mem mem;
+
+#endif /* ROOT_MEM_H */
diff --git a/gcc/d/dfrontend/root.h b/gcc/d/dfrontend/root.h
new file mode 100644
index 00000000000..bea105303e0
--- /dev/null
+++ b/gcc/d/dfrontend/root.h
@@ -0,0 +1,27 @@
+
+/* Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/dlang/dmd/blob/master/src/root/root.h
+ */
+
+#ifndef ROOT_H
+#define ROOT_H
+
+#if __DMC__
+#pragma once
+#endif
+
+#include "object.h"
+
+#include "filename.h"
+
+#include "file.h"
+
+#include "outbuffer.h"
+
+#include "array.h"
+
+#endif
diff --git a/gcc/d/dfrontend/rootobject.c b/gcc/d/dfrontend/rootobject.c
new file mode 100644
index 00000000000..bef0f25d951
--- /dev/null
+++ b/gcc/d/dfrontend/rootobject.c
@@ -0,0 +1,50 @@
+/* Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/object.c
+ */
+
+#include <stdio.h>
+
+#include "object.h"
+#include "outbuffer.h"
+
+/****************************** Object ********************************/
+
+bool RootObject::equals(RootObject *o)
+{
+    return o == this;
+}
+
+int RootObject::compare(RootObject *obj)
+{
+    size_t lhs = (size_t)this;
+    size_t rhs = (size_t)obj;
+    if (lhs < rhs)
+        return -1;
+    else if (lhs > rhs)
+        return 1;
+    return 0;
+}
+
+void RootObject::print()
+{
+    printf("%s %p\n", toChars(), this);
+}
+
+const char *RootObject::toChars()
+{
+    return (char *)"Object";
+}
+
+int RootObject::dyncast() const
+{
+    return DYNCAST_OBJECT;
+}
+
+void RootObject::toBuffer(OutBuffer *b)
+{
+    b->writestring("Object");
+}
diff --git a/gcc/d/dfrontend/safe.c b/gcc/d/dfrontend/safe.c
new file mode 100644
index 00000000000..035f9e0b4d4
--- /dev/null
+++ b/gcc/d/dfrontend/safe.c
@@ -0,0 +1,80 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2017 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/safe.c
+ */
+
+#include "expression.h"
+#include "scope.h"
+#include "aggregate.h"
+#include "target.h"
+
+/*************************************************************
+ * Check for unsafe access in @safe code:
+ * 1. read overlapped pointers
+ * 2. write misaligned pointers
+ * 3. write overlapped storage classes
+ * Print error if unsafe.
+ * Params:
+ *      sc = scope
+ *      e = expression to check
+ *      readonly = if access is read-only
+ *      printmsg = print error message if true
+ * Returns:
+ *      true if error
+ */
+
+bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg)
+{
+    if (e->op != TOKdotvar)
+        return false;
+    DotVarExp *dve = (DotVarExp *)e;
+    if (VarDeclaration *v = dve->var->isVarDeclaration())
+    {
+        if (sc->intypeof || !sc->func || !sc->func->isSafeBypassingInference())
+            return false;
+
+        AggregateDeclaration *ad = v->toParent2()->isAggregateDeclaration();
+        if (!ad)
+            return false;
+
+        if (v->overlapped && v->type->hasPointers() && sc->func->setUnsafe())
+        {
+            if (printmsg)
+                e->error("field %s.%s cannot access pointers in @safe code that overlap other fields",
+                    ad->toChars(), v->toChars());
+            return true;
+        }
+
+        if (readonly || !e->type->isMutable())
+            return false;
+
+        if (v->type->hasPointers() && v->type->toBasetype()->ty != Tstruct)
+        {
+            if ((ad->type->alignment() < Target::ptrsize ||
+                 (v->offset & (Target::ptrsize - 1))) &&
+                sc->func->setUnsafe())
+            {
+                if (printmsg)
+                    e->error("field %s.%s cannot modify misaligned pointers in @safe code",
+                        ad->toChars(), v->toChars());
+                return true;
+            }
+        }
+
+        if (v->overlapUnsafe && sc->func->setUnsafe())
+        {
+            if (printmsg)
+                e->error("field %s.%s cannot modify fields in @safe code that overlap fields with other storage classes",
+                    ad->toChars(), v->toChars());
+            return true;
+        }
+    }
+    return false;
+}
+
diff --git a/gcc/d/dfrontend/sapply.c b/gcc/d/dfrontend/sapply.c
new file mode 100644
index 00000000000..c4fc6900e24
--- /dev/null
+++ b/gcc/d/dfrontend/sapply.c
@@ -0,0 +1,157 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/sapply.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "statement.h"
+#include "visitor.h"
+
+
+/**************************************
+ * A Statement tree walker that will visit each Statement s in the tree,
+ * in depth-first evaluation order, and call fp(s,param) on it.
+ * fp() signals whether the walking continues with its return value:
+ * Returns:
+ *      0       continue
+ *      1       done
+ * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
+ * Creating an iterator for this would be much more complex.
+ */
+
+class PostorderStatementVisitor : public StoppableVisitor
+{
+public:
+    StoppableVisitor *v;
+    PostorderStatementVisitor(StoppableVisitor *v) : v(v) {}
+
+    bool doCond(Statement *s)
+    {
+        if (!stop && s)
+            s->accept(this);
+        return stop;
+    }
+    bool applyTo(Statement *s)
+    {
+        s->accept(v);
+        stop = v->stop;
+        return true;
+    }
+
+    void visit(Statement *s)
+    {
+        applyTo(s);
+    }
+    void visit(PeelStatement *s)
+    {
+        doCond(s->s) || applyTo(s);
+    }
+    void visit(CompoundStatement *s)
+    {
+        for (size_t i = 0; i < s->statements->dim; i++)
+            if (doCond((*s->statements)[i]))
+                return;
+        applyTo(s);
+    }
+    void visit(UnrolledLoopStatement *s)
+    {
+        for (size_t i = 0; i < s->statements->dim; i++)
+            if (doCond((*s->statements)[i]))
+                return;
+        applyTo(s);
+    }
+    void visit(ScopeStatement *s)
+    {
+        doCond(s->statement) || applyTo(s);
+    }
+    void visit(WhileStatement *s)
+    {
+        doCond(s->_body) || applyTo(s);
+    }
+    void visit(DoStatement *s)
+    {
+        doCond(s->_body) || applyTo(s);
+    }
+    void visit(ForStatement *s)
+    {
+        doCond(s->_init) || doCond(s->_body) || applyTo(s);
+    }
+    void visit(ForeachStatement *s)
+    {
+        doCond(s->_body) || applyTo(s);
+    }
+    void visit(ForeachRangeStatement *s)
+    {
+        doCond(s->_body) || applyTo(s);
+    }
+    void visit(IfStatement *s)
+    {
+        doCond(s->ifbody) || doCond(s->elsebody) || applyTo(s);
+    }
+    void visit(PragmaStatement *s)
+    {
+        doCond(s->_body) || applyTo(s);
+    }
+    void visit(SwitchStatement *s)
+    {
+        doCond(s->_body) || applyTo(s);
+    }
+    void visit(CaseStatement *s)
+    {
+        doCond(s->statement) || applyTo(s);
+    }
+    void visit(DefaultStatement *s)
+    {
+        doCond(s->statement) || applyTo(s);
+    }
+    void visit(SynchronizedStatement *s)
+    {
+        doCond(s->_body) || applyTo(s);
+    }
+    void visit(WithStatement *s)
+    {
+        doCond(s->_body) || applyTo(s);
+    }
+    void visit(TryCatchStatement *s)
+    {
+        if (doCond(s->_body))
+            return;
+
+        for (size_t i = 0; i < s->catches->dim; i++)
+            if (doCond((*s->catches)[i]->handler))
+                return;
+        applyTo(s);
+    }
+    void visit(TryFinallyStatement *s)
+    {
+        doCond(s->_body) || doCond(s->finalbody) || applyTo(s);
+    }
+    void visit(OnScopeStatement *s)
+    {
+        doCond(s->statement) || applyTo(s);
+    }
+    void visit(DebugStatement *s)
+    {
+        doCond(s->statement) || applyTo(s);
+    }
+    void visit(LabelStatement *s)
+    {
+        doCond(s->statement) || applyTo(s);
+    }
+};
+
+bool walkPostorder(Statement *s, StoppableVisitor *v)
+{
+    PostorderStatementVisitor pv(v);
+    s->accept(&pv);
+    return v->stop;
+}
diff --git a/gcc/d/dfrontend/scope.h b/gcc/d/dfrontend/scope.h
new file mode 100644
index 00000000000..5bf7ce600bc
--- /dev/null
+++ b/gcc/d/dfrontend/scope.h
@@ -0,0 +1,165 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/scope.h
+ */
+
+#ifndef DMD_SCOPE_H
+#define DMD_SCOPE_H
+
+#ifdef __DMC__
+#pragma once
+#endif
+
+class Dsymbol;
+class ScopeDsymbol;
+class Identifier;
+class Module;
+class Statement;
+class SwitchStatement;
+class TryFinallyStatement;
+class LabelStatement;
+class ForeachStatement;
+class ClassDeclaration;
+class AggregateDeclaration;
+class FuncDeclaration;
+class UserAttributeDeclaration;
+struct DocComment;
+struct AA;
+class TemplateInstance;
+
+#include "dsymbol.h"
+
+#if __GNUC__
+// Requires a full definition for LINK
+#include "mars.h"
+#else
+enum LINK;
+enum PINLINE;
+#endif
+
+#define CSXthis_ctor    1       // called this()
+#define CSXsuper_ctor   2       // called super()
+#define CSXthis         4       // referenced this
+#define CSXsuper        8       // referenced super
+#define CSXlabel        0x10    // seen a label
+#define CSXreturn       0x20    // seen a return statement
+#define CSXany_ctor     0x40    // either this() or super() was called
+#define CSXhalt         0x80    // assert(0)
+
+// Flags that would not be inherited beyond scope nesting
+#define SCOPEctor           0x0001  // constructor type
+#define SCOPEcondition      0x0004  // inside static if/assert condition
+#define SCOPEdebug          0x0008  // inside debug conditional
+
+// Flags that would be inherited beyond scope nesting
+#define SCOPEnoaccesscheck  0x0002  // don't do access checks
+#define SCOPEconstraint     0x0010  // inside template constraint
+#define SCOPEinvariant      0x0020  // inside invariant code
+#define SCOPErequire        0x0040  // inside in contract code
+#define SCOPEensure         0x0060  // inside out contract code
+#define SCOPEcontract       0x0060  // [mask] we're inside contract code
+#define SCOPEctfe           0x0080  // inside a ctfe-only expression
+#define SCOPEcompile        0x0100  // inside __traits(compile)
+#define SCOPEignoresymbolvisibility 0x0200  // ignore symbol visibility (Bugzilla 15907)
+#define SCOPEfullinst       0x1000  // fully instantiate templates
+
+#define SCOPEfree           0x8000  // is on free list
+
+struct Scope
+{
+    Scope *enclosing;           // enclosing Scope
+
+    Module *_module;            // Root module
+    ScopeDsymbol *scopesym;     // current symbol
+    ScopeDsymbol *sds;          // if in static if, and declaring new symbols,
+                                // sds gets the addMember()
+    FuncDeclaration *func;      // function we are in
+    Dsymbol *parent;            // parent to use
+    LabelStatement *slabel;     // enclosing labelled statement
+    SwitchStatement *sw;        // enclosing switch statement
+    TryFinallyStatement *tf;    // enclosing try finally statement
+    OnScopeStatement *os;       // enclosing scope(xxx) statement
+    Statement *sbreak;          // enclosing statement that supports "break"
+    Statement *scontinue;       // enclosing statement that supports "continue"
+    ForeachStatement *fes;      // if nested function for ForeachStatement, this is it
+    Scope *callsc;              // used for __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__
+    int inunion;                // we're processing members of a union
+    int nofree;                 // set if shouldn't free it
+    int noctor;                 // set if constructor calls aren't allowed
+    int intypeof;               // in typeof(exp)
+    VarDeclaration *lastVar;    // Previous symbol used to prevent goto-skips-init
+
+    /* If  minst && !tinst, it's in definitely non-speculative scope (eg. module member scope).
+     * If !minst && !tinst, it's in definitely speculative scope (eg. template constraint).
+     * If  minst &&  tinst, it's in instantiated code scope without speculation.
+     * If !minst &&  tinst, it's in instantiated code scope with speculation.
+     */
+    Module *minst;              // root module where the instantiated templates should belong to
+    TemplateInstance *tinst;    // enclosing template instance
+
+    unsigned callSuper;         // primitive flow analysis for constructors
+    unsigned *fieldinit;
+    size_t fieldinit_dim;
+
+    AlignDeclaration *aligndecl;    // alignment for struct members
+
+    LINK linkage;               // linkage for external functions
+    CPPMANGLE cppmangle;        // C++ mangle type
+    PINLINE inlining;            // inlining strategy for functions
+
+    Prot protection;            // protection for class members
+    int explicitProtection;     // set if in an explicit protection attribute
+
+    StorageClass stc;           // storage class
+
+    DeprecatedDeclaration *depdecl; // customized deprecation message
+
+    unsigned flags;
+
+    UserAttributeDeclaration *userAttribDecl;   // user defined attributes
+
+    DocComment *lastdc;         // documentation comment for last symbol at this scope
+    AA *anchorCounts;           // lookup duplicate anchor name count
+    Identifier *prevAnchor;     // qualified symbol name of last doc anchor
+
+    static Scope *freelist;
+    static Scope *alloc();
+    static Scope *createGlobal(Module *module);
+
+    Scope();
+
+    Scope *copy();
+
+    Scope *push();
+    Scope *push(ScopeDsymbol *ss);
+    Scope *pop();
+
+    Scope *startCTFE();
+    Scope *endCTFE();
+
+    void mergeCallSuper(Loc loc, unsigned cs);
+
+    unsigned *saveFieldInit();
+    void mergeFieldInit(Loc loc, unsigned *cses);
+
+    Module *instantiatingModule();
+
+    Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone);
+    static void deprecation10378(Loc loc, Dsymbol *sold, Dsymbol *snew);
+    Dsymbol *search_correct(Identifier *ident);
+    Dsymbol *insert(Dsymbol *s);
+
+    ClassDeclaration *getClassScope();
+    AggregateDeclaration *getStructClassScope();
+    void setNoFree();
+
+    structalign_t alignment();
+};
+
+#endif /* DMD_SCOPE_H */
diff --git a/gcc/d/dfrontend/sideeffect.c b/gcc/d/dfrontend/sideeffect.c
new file mode 100644
index 00000000000..dfeae66a70c
--- /dev/null
+++ b/gcc/d/dfrontend/sideeffect.c
@@ -0,0 +1,440 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/sideeffect.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "init.h"
+#include "expression.h"
+#include "template.h"
+#include "statement.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "attrib.h"
+#include "tokens.h"
+
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+bool lambdaHasSideEffect(Expression *e);
+Expression *semantic(Expression *e, Scope *sc);
+
+/**************************************************
+ * Front-end expression rewriting should create temporary variables for
+ * non trivial sub-expressions in order to:
+ *  1. save evaluation order
+ *  2. prevent sharing of sub-expression in AST
+ */
+bool isTrivialExp(Expression *e)
+{
+    class IsTrivialExp : public StoppableVisitor
+    {
+    public:
+        IsTrivialExp() {}
+
+        void visit(Expression *e)
+        {
+            /* Bugzilla 11201: CallExp is always non trivial expression,
+             * especially for inlining.
+             */
+            if (e->op == TOKcall)
+            {
+                stop = true;
+                return;
+            }
+
+            // stop walking if we determine this expression has side effects
+            stop = lambdaHasSideEffect(e);
+        }
+    };
+
+    IsTrivialExp v;
+    return walkPostorder(e, &v) == false;
+}
+
+/********************************************
+ * Determine if Expression has any side effects.
+ */
+
+bool hasSideEffect(Expression *e)
+{
+    class LambdaHasSideEffect : public StoppableVisitor
+    {
+    public:
+        LambdaHasSideEffect() {}
+
+        void visit(Expression *e)
+        {
+            // stop walking if we determine this expression has side effects
+            stop = lambdaHasSideEffect(e);
+        }
+    };
+
+    LambdaHasSideEffect v;
+    return walkPostorder(e, &v);
+}
+
+/********************************************
+ * Determine if the call of f, or function type or delegate type t1, has any side effects.
+ * Returns:
+ *      0   has any side effects
+ *      1   nothrow + constant purity
+ *      2   nothrow + strong purity
+ */
+
+int callSideEffectLevel(FuncDeclaration *f)
+{
+    /* Bugzilla 12760: ctor call always has side effects.
+     */
+    if (f->isCtorDeclaration())
+        return 0;
+
+    assert(f->type->ty == Tfunction);
+    TypeFunction *tf = (TypeFunction *)f->type;
+    if (tf->isnothrow)
+    {
+        PURE purity = f->isPure();
+        if (purity == PUREstrong)
+            return 2;
+        if (purity == PUREconst)
+            return 1;
+    }
+    return 0;
+}
+
+int callSideEffectLevel(Type *t)
+{
+    t = t->toBasetype();
+
+    TypeFunction *tf;
+    if (t->ty == Tdelegate)
+        tf = (TypeFunction *)((TypeDelegate *)t)->next;
+    else
+    {
+        assert(t->ty == Tfunction);
+        tf = (TypeFunction *)t;
+    }
+
+    tf->purityLevel();
+    PURE purity = tf->purity;
+    if (t->ty == Tdelegate && purity > PUREweak)
+    {
+        if (tf->isMutable())
+            purity = PUREweak;
+        else if (!tf->isImmutable())
+            purity = PUREconst;
+    }
+
+    if (tf->isnothrow)
+    {
+        if (purity == PUREstrong)
+            return 2;
+        if (purity == PUREconst)
+            return 1;
+    }
+    return 0;
+}
+
+bool lambdaHasSideEffect(Expression *e)
+{
+    switch (e->op)
+    {
+        // Sort the cases by most frequently used first
+        case TOKassign:
+        case TOKplusplus:
+        case TOKminusminus:
+        case TOKdeclaration:
+        case TOKconstruct:
+        case TOKblit:
+        case TOKaddass:
+        case TOKminass:
+        case TOKcatass:
+        case TOKmulass:
+        case TOKdivass:
+        case TOKmodass:
+        case TOKshlass:
+        case TOKshrass:
+        case TOKushrass:
+        case TOKandass:
+        case TOKorass:
+        case TOKxorass:
+        case TOKpowass:
+        case TOKin:
+        case TOKremove:
+        case TOKassert:
+        case TOKhalt:
+        case TOKdelete:
+        case TOKnew:
+        case TOKnewanonclass:
+            return true;
+
+        case TOKcall:
+        {
+            CallExp *ce = (CallExp *)e;
+            /* Calling a function or delegate that is pure nothrow
+             * has no side effects.
+             */
+            if (ce->e1->type)
+            {
+                Type *t = ce->e1->type->toBasetype();
+                if (t->ty == Tdelegate)
+                    t = ((TypeDelegate *)t)->next;
+                if (t->ty == Tfunction &&
+                    (ce->f ? callSideEffectLevel(ce->f)
+                           : callSideEffectLevel(ce->e1->type)) > 0)
+                {
+                }
+                else
+                    return true;
+            }
+            break;
+        }
+
+        case TOKcast:
+        {
+            CastExp *ce = (CastExp *)e;
+            /* if:
+             *  cast(classtype)func()  // because it may throw
+             */
+            if (ce->to->ty == Tclass && ce->e1->op == TOKcall && ce->e1->type->ty == Tclass)
+                return true;
+            break;
+        }
+
+        default:
+            break;
+    }
+    return false;
+}
+
+
+/***********************************
+ * The result of this expression will be discarded.
+ * Print error messages if the operation has no side effects (and hence is meaningless).
+ * Returns:
+ *      true if expression has no side effects
+ */
+bool discardValue(Expression *e)
+{
+    if (lambdaHasSideEffect(e))     // check side-effect shallowly
+        return false;
+    switch (e->op)
+    {
+        case TOKcast:
+        {
+            CastExp *ce = (CastExp *)e;
+            if (ce->to->equals(Type::tvoid))
+            {
+                /*
+                 * Don't complain about an expression with no effect if it was cast to void
+                 */
+                return false;
+            }
+            break;          // complain
+        }
+
+        case TOKerror:
+            return false;
+
+        case TOKvar:
+        {
+            VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
+            if (v && (v->storage_class & STCtemp))
+            {
+                // Bugzilla 5810: Don't complain about an internal generated variable.
+                return false;
+            }
+            break;
+        }
+        case TOKcall:
+            /* Issue 3882: */
+            if (global.params.warnings && !global.gag)
+            {
+                CallExp *ce = (CallExp *)e;
+                if (e->type->ty == Tvoid)
+                {
+                    /* Don't complain about calling void-returning functions with no side-effect,
+                     * because purity and nothrow are inferred, and because some of the
+                     * runtime library depends on it. Needs more investigation.
+                     *
+                     * One possible solution is to restrict this message to only be called in hierarchies that
+                     * never call assert (and or not called from inside unittest blocks)
+                     */
+                }
+                else if (ce->e1->type)
+                {
+                    Type *t = ce->e1->type->toBasetype();
+                    if (t->ty == Tdelegate)
+                        t = ((TypeDelegate *)t)->next;
+                    if (t->ty == Tfunction &&
+                        (ce->f ? callSideEffectLevel(ce->f)
+                               : callSideEffectLevel(ce->e1->type)) > 0)
+                    {
+                        const char *s;
+                        if (ce->f)
+                            s = ce->f->toPrettyChars();
+                        else if (ce->e1->op == TOKstar)
+                        {
+                            // print 'fp' if ce->e1 is (*fp)
+                            s = ((PtrExp *)ce->e1)->e1->toChars();
+                        }
+                        else
+                            s = ce->e1->toChars();
+
+                        e->warning("calling %s without side effects discards return value of type %s, prepend a cast(void) if intentional",
+                                   s, e->type->toChars());
+                    }
+                }
+            }
+            return false;
+
+        case TOKscope:
+            e->error("%s has no effect", e->toChars());
+            return true;
+
+        case TOKandand:
+        {
+            AndAndExp *aae = (AndAndExp *)e;
+            return discardValue(aae->e2);
+        }
+
+        case TOKoror:
+        {
+            OrOrExp *ooe = (OrOrExp *)e;
+            return discardValue(ooe->e2);
+        }
+
+        case TOKquestion:
+        {
+            CondExp *ce = (CondExp *)e;
+
+            /* Bugzilla 6178 & 14089: Either CondExp::e1 or e2 may have
+             * redundant expression to make those types common. For example:
+             *
+             *  struct S { this(int n); int v; alias v this; }
+             *  S[int] aa;
+             *  aa[1] = 0;
+             *
+             * The last assignment statement will be rewitten to:
+             *
+             *  1 in aa ? aa[1].value = 0 : (aa[1] = 0, aa[1].this(0)).value;
+             *
+             * The last DotVarExp is necessary to take assigned value.
+             *
+             *  int value = (aa[1] = 0);    // value = aa[1].value
+             *
+             * To avoid false error, discardValue() should be called only when
+             * the both tops of e1 and e2 have actually no side effects.
+             */
+            if (!lambdaHasSideEffect(ce->e1) &&
+                !lambdaHasSideEffect(ce->e2))
+            {
+                return discardValue(ce->e1) |
+                       discardValue(ce->e2);
+            }
+            return false;
+        }
+
+        case TOKcomma:
+        {
+            CommaExp *ce = (CommaExp *)e;
+            /* Check for compiler-generated code of the form  auto __tmp, e, __tmp;
+             * In such cases, only check e for side effect (it's OK for __tmp to have
+             * no side effect).
+             * See Bugzilla 4231 for discussion
+             */
+            CommaExp *firstComma = ce;
+            while (firstComma->e1->op == TOKcomma)
+                firstComma = (CommaExp *)firstComma->e1;
+            if (firstComma->e1->op == TOKdeclaration &&
+                ce->e2->op == TOKvar &&
+                ((DeclarationExp *)firstComma->e1)->declaration == ((VarExp*)ce->e2)->var)
+            {
+                return false;
+            }
+            // Don't check e1 until we cast(void) the a,b code generation
+            //discardValue(ce->e1);
+            return discardValue(ce->e2);
+        }
+
+        case TOKtuple:
+            /* Pass without complaint if any of the tuple elements have side effects.
+             * Ideally any tuple elements with no side effects should raise an error,
+             * this needs more investigation as to what is the right thing to do.
+             */
+            if (!hasSideEffect(e))
+                break;
+            return false;
+
+        default:
+            break;
+    }
+    e->error("%s has no effect in expression (%s)", Token::toChars(e->op), e->toChars());
+    return true;
+}
+
+/**************************************************
+ * Build a temporary variable to copy the value of e into.
+ * Params:
+ *  stc = storage classes will be added to the made temporary variable
+ *  name = name for temporary variable
+ *  e = original expression
+ * Returns:
+ *  Newly created temporary variable.
+ */
+VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e)
+{
+    assert(name && name[0] == '_' && name[1] == '_');
+    Identifier *id = Identifier::generateId(name);
+    ExpInitializer *ez = new ExpInitializer(e->loc, e);
+    VarDeclaration *vd = new VarDeclaration(e->loc, e->type, id, ez);
+    vd->storage_class = stc;
+    vd->storage_class |= STCtemp;
+    vd->storage_class |= STCctfe; // temporary is always CTFEable
+    return vd;
+}
+
+/**************************************************
+ * Build a temporary variable to extract e's evaluation, if e is not trivial.
+ * Params:
+ *  sc = scope
+ *  name = name for temporary variable
+ *  e0 = a new side effect part will be appended to it.
+ *  e = original expression
+ *  alwaysCopy = if true, build new temporary variable even if e is trivial.
+ * Returns:
+ *  When e is trivial and alwaysCopy == false, e itself is returned.
+ *  Otherwise, a new VarExp is returned.
+ * Note:
+ *  e's lvalue-ness will be handled well by STCref or STCrvalue.
+ */
+Expression *extractSideEffect(Scope *sc, const char *name,
+    Expression **e0, Expression *e, bool alwaysCopy = false)
+{
+    if (!alwaysCopy && isTrivialExp(e))
+        return e;
+
+    VarDeclaration *vd = copyToTemp(0, name, e);
+    if (e->isLvalue())
+        vd->storage_class |= STCref;
+    else
+        vd->storage_class |= STCrvalue;
+
+    Expression *de = new DeclarationExp(vd->loc, vd);
+    Expression *ve = new VarExp(vd->loc, vd);
+    de = semantic(de, sc);
+    ve = semantic(ve, sc);
+
+    *e0 = Expression::combine(*e0, de);
+    return ve;
+}
diff --git a/gcc/d/dfrontend/speller.c b/gcc/d/dfrontend/speller.c
new file mode 100644
index 00000000000..07b48423298
--- /dev/null
+++ b/gcc/d/dfrontend/speller.c
@@ -0,0 +1,295 @@
+
+/* Copyright (c) 2010-2014 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/speller.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+
+#if __sun || _MSC_VER
+#include <alloca.h>
+#endif
+
+#include "speller.h"
+
+const char idchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+
+/**************************************************
+ * combine a new result from the spell checker to
+ * find the one with the closest symbol with
+ * respect to the cost defined by the search function
+ * Input/Output:
+ *      p       best found spelling (NULL if none found yet)
+ *      cost    cost of p (INT_MAX if none found yet)
+ * Input:
+ *      np      new found spelling (NULL if none found)
+ *      ncost   cost of np if non-NULL
+ * Returns:
+ *      true    if the cost is less or equal 0
+ *      false   otherwise
+ */
+bool combineSpellerResult(void*& p, int& cost, void* np, int ncost)
+{
+    if (np && ncost < cost)
+    {
+        p = np;
+        cost = ncost;
+        if (cost <= 0)
+            return true;
+    }
+    return false;
+}
+
+void *spellerY(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg,
+        const char *charset, size_t index, int* cost)
+{
+    if (!seedlen)
+        return NULL;
+    assert(seed[seedlen] == 0);
+
+    char tmp[30];
+    char *buf;
+    if (seedlen <= sizeof(tmp) - 2)
+        buf = tmp;
+    else
+    {
+        buf = (char *)alloca(seedlen + 2);    // leave space for extra char
+        if (!buf)
+            return NULL;                      // no matches
+    }
+
+    memcpy(buf, seed, index);
+    *cost = INT_MAX;
+    void* p = NULL;
+    int ncost;
+
+    /* Delete at seed[index] */
+    if (index < seedlen)
+    {
+        memcpy(buf + index, seed + index + 1, seedlen - index);
+        assert(buf[seedlen - 1] == 0);
+        void* np = (*fp)(fparg, buf, &ncost);
+        if (combineSpellerResult(p, *cost, np, ncost))
+            return p;
+    }
+
+    if (charset && *charset)
+    {
+        /* Substitutions */
+        if (index < seedlen)
+        {
+            memcpy(buf, seed, seedlen + 1);
+            for (const char *s = charset; *s; s++)
+            {
+                buf[index] = *s;
+
+                //printf("sub buf = '%s'\n", buf);
+                void* np = (*fp)(fparg, buf, &ncost);
+                if (combineSpellerResult(p, *cost, np, ncost))
+                    return p;
+            }
+            assert(buf[seedlen] == 0);
+        }
+
+        /* Insertions */
+        memcpy (buf + index + 1, seed + index, seedlen + 1 - index);
+
+        for (const char *s = charset; *s; s++)
+        {
+            buf[index] = *s;
+
+            //printf("ins buf = '%s'\n", buf);
+            void* np = (*fp)(fparg, buf, &ncost);
+            if (combineSpellerResult(p, *cost, np, ncost))
+                return p;
+        }
+        assert(buf[seedlen + 1] == 0);
+    }
+
+    return p;                // return "best" result
+}
+
+void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg,
+        const char *charset, int flag)
+{
+    if (!seedlen)
+        return NULL;
+
+    char tmp[30];
+    char *buf;
+    if (seedlen <= sizeof(tmp) - 2)
+        buf = tmp;
+    else
+    {
+        buf = (char *)alloca(seedlen + 2);    // leave space for extra char
+        if (!buf)
+            return NULL;                      // no matches
+    }
+    int cost = INT_MAX, ncost;
+    void *p = NULL, *np;
+
+    /* Deletions */
+    memcpy(buf, seed + 1, seedlen);
+    for (size_t i = 0; i < seedlen; i++)
+    {
+        //printf("del buf = '%s'\n", buf);
+        if (flag)
+            np = spellerY(buf, seedlen - 1, fp, fparg, charset, i, &ncost);
+        else
+            np = (*fp)(fparg, buf, &ncost);
+        if (combineSpellerResult(p, cost, np, ncost))
+            return p;
+
+        buf[i] = seed[i];
+    }
+
+    /* Transpositions */
+    if (!flag)
+    {
+        memcpy(buf, seed, seedlen + 1);
+        for (size_t i = 0; i + 1 < seedlen; i++)
+        {
+            // swap [i] and [i + 1]
+            buf[i] = seed[i + 1];
+            buf[i + 1] = seed[i];
+
+            //printf("tra buf = '%s'\n", buf);
+            if (combineSpellerResult(p, cost, (*fp)(fparg, buf, &ncost), ncost))
+                return p;
+
+            buf[i] = seed[i];
+        }
+    }
+
+    if (charset && *charset)
+    {
+        /* Substitutions */
+        memcpy(buf, seed, seedlen + 1);
+        for (size_t i = 0; i < seedlen; i++)
+        {
+            for (const char *s = charset; *s; s++)
+            {
+                buf[i] = *s;
+
+                //printf("sub buf = '%s'\n", buf);
+                if (flag)
+                    np = spellerY(buf, seedlen, fp, fparg, charset, i + 1, &ncost);
+                else
+                    np = (*fp)(fparg, buf, &ncost);
+                if (combineSpellerResult(p, cost, np, ncost))
+                    return p;
+            }
+            buf[i] = seed[i];
+        }
+
+        /* Insertions */
+        memcpy(buf + 1, seed, seedlen + 1);
+        for (size_t i = 0; i <= seedlen; i++)      // yes, do seedlen+1 iterations
+        {
+            for (const char *s = charset; *s; s++)
+            {
+                buf[i] = *s;
+
+                //printf("ins buf = '%s'\n", buf);
+                if (flag)
+                    np = spellerY(buf, seedlen + 1, fp, fparg, charset, i + 1, &ncost);
+                else
+                    np = (*fp)(fparg, buf, &ncost);
+                if (combineSpellerResult(p, cost, np, ncost))
+                    return p;
+            }
+            buf[i] = seed[i];   // going past end of seed[] is ok, as we hit the 0
+        }
+    }
+
+    return p;                // return "best" result
+}
+
+/**************************************************
+ * Looks for correct spelling.
+ * Currently only looks a 'distance' of one from the seed[].
+ * This does an exhaustive search, so can potentially be very slow.
+ * Input:
+ *      seed            wrongly spelled word
+ *      fp              search function
+ *      fparg           argument to search function
+ *      charset         character set
+ * Returns:
+ *      NULL            no correct spellings found
+ *      void*           value returned by fp() for first possible correct spelling
+ */
+
+void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset)
+{
+    size_t seedlen = strlen(seed);
+    size_t maxdist = seedlen < 4 ? seedlen / 2 : 2;
+    for (int distance = 0; distance < maxdist; distance++)
+    {   void *p = spellerX(seed, seedlen, fp, fparg, charset, distance);
+        if (p)
+            return p;
+//      if (seedlen > 10)
+//          break;
+    }
+    return NULL;   // didn't find it
+}
+
+
+#if UNITTEST
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+void *speller_test(void *fparg, const char *s, int* cost)
+{
+    //printf("speller_test(%s, %s)\n", fparg, s);
+    *cost = 0;
+    if (strcmp((char *)fparg, s) == 0)
+        return fparg;
+    return NULL;
+}
+
+void unittest_speller()
+{
+    static const char *cases[][3] =
+    {
+        { "hello", "hell",  "y" },
+        { "hello", "hel",   "y" },
+        { "hello", "ello",  "y" },
+        { "hello", "llo",   "y" },
+        { "hello", "hellox",  "y" },
+        { "hello", "helloxy",  "y" },
+        { "hello", "xhello",  "y" },
+        { "hello", "xyhello",  "y" },
+        { "hello", "ehllo",  "y" },
+        { "hello", "helol",  "y" },
+        { "hello", "abcd",  "n" },
+        { "hello", "helxxlo", "y" },
+        { "hello", "ehlxxlo", "n" },
+        { "hello", "heaao", "y" },
+        { "_123456789_123456789_123456789_123456789", "_123456789_123456789_123456789_12345678", "y" },
+        { NULL, NULL, NULL }
+    };
+    //printf("unittest_speller()\n");
+    const void *p = speller("hello", &speller_test, (void *)"hell", idchars);
+    assert(p != NULL);
+    for (int i = 0; cases[i][0]; i++)
+    {
+        //printf("case [%d]\n", i);
+        void *p2 = speller(cases[i][0], &speller_test, (void *)cases[i][1], idchars);
+        if (p2)
+            assert(cases[i][2][0] == 'y');
+        else
+            assert(cases[i][2][0] == 'n');
+    }
+    //printf("unittest_speller() success\n");
+}
+
+#endif
diff --git a/gcc/d/dfrontend/speller.h b/gcc/d/dfrontend/speller.h
new file mode 100644
index 00000000000..bfc6858d898
--- /dev/null
+++ b/gcc/d/dfrontend/speller.h
@@ -0,0 +1,15 @@
+
+/* Copyright (c) 2010-2014 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/speller.h
+ */
+
+typedef void *(fp_speller_t)(void *, const char *, int*);
+
+extern const char idchars[];
+
+void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset);
+
diff --git a/gcc/d/dfrontend/statement.c b/gcc/d/dfrontend/statement.c
new file mode 100644
index 00000000000..af390cacba9
--- /dev/null
+++ b/gcc/d/dfrontend/statement.c
@@ -0,0 +1,1656 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/statement.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "statement.h"
+#include "expression.h"
+#include "cond.h"
+#include "init.h"
+#include "staticassert.h"
+#include "scope.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+#include "hdrgen.h"
+#include "parse.h"
+#include "template.h"
+#include "attrib.h"
+#include "import.h"
+
+bool walkPostorder(Statement *s, StoppableVisitor *v);
+StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f);
+bool checkEscapeRef(Scope *sc, Expression *e, bool gag);
+VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
+Expression *semantic(Expression *e, Scope *sc);
+
+Identifier *fixupLabelName(Scope *sc, Identifier *ident)
+{
+    unsigned flags = (sc->flags & SCOPEcontract);
+    const char *id = ident->toChars();
+    if (flags && flags != SCOPEinvariant &&
+        !(id[0] == '_' && id[1] == '_'))
+    {
+        /* CTFE requires FuncDeclaration::labtab for the interpretation.
+         * So fixing the label name inside in/out contracts is necessary
+         * for the uniqueness in labtab.
+         */
+        const char *prefix = flags == SCOPErequire ? "__in_" : "__out_";
+        OutBuffer buf;
+        buf.printf("%s%s", prefix, ident->toChars());
+
+        const char *name = buf.extractString();
+        ident = Identifier::idPool(name);
+    }
+    return ident;
+}
+
+LabelStatement *checkLabeledLoop(Scope *sc, Statement *statement)
+{
+    if (sc->slabel && sc->slabel->statement == statement)
+    {
+        return sc->slabel;
+    }
+    return NULL;
+}
+
+/***********************************************************
+ * Check an assignment is used as a condition.
+ * Intended to be use before the `semantic` call on `e`.
+ * Params:
+ *  e = condition expression which is not yet run semantic analysis.
+ * Returns:
+ *  `e` or ErrorExp.
+ */
+Expression *checkAssignmentAsCondition(Expression *e)
+{
+    Expression *ec = e;
+    while (ec->op == TOKcomma)
+        ec = ((CommaExp *)ec)->e2;
+    if (ec->op == TOKassign)
+    {
+        ec->error("assignment cannot be used as a condition, perhaps == was meant?");
+        return new ErrorExp();
+    }
+    return e;
+}
+
+/******************************** Statement ***************************/
+
+Statement::Statement(Loc loc)
+    : loc(loc)
+{
+    // If this is an in{} contract scope statement (skip for determining
+    //  inlineStatus of a function body for header content)
+}
+
+Statement *Statement::syntaxCopy()
+{
+    assert(0);
+    return NULL;
+}
+
+void Statement::print()
+{
+    fprintf(stderr, "%s\n", toChars());
+    fflush(stderr);
+}
+
+const char *Statement::toChars()
+{
+    HdrGenState hgs;
+
+    OutBuffer buf;
+    ::toCBuffer(this, &buf, &hgs);
+    return buf.extractString();
+}
+
+
+void Statement::error(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::verror(loc, format, ap);
+    va_end( ap );
+}
+
+void Statement::warning(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::vwarning(loc, format, ap);
+    va_end( ap );
+}
+
+void Statement::deprecation(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::vdeprecation(loc, format, ap);
+    va_end( ap );
+}
+
+bool Statement::hasBreak()
+{
+    //printf("Statement::hasBreak()\n");
+    return false;
+}
+
+bool Statement::hasContinue()
+{
+    return false;
+}
+
+/* ============================================== */
+// true if statement uses exception handling
+
+bool Statement::usesEH()
+{
+    class UsesEH : public StoppableVisitor
+    {
+    public:
+        void visit(Statement *s)             {}
+        void visit(TryCatchStatement *s)     { stop = true; }
+        void visit(TryFinallyStatement *s)   { stop = true; }
+        void visit(OnScopeStatement *s)      { stop = true; }
+        void visit(SynchronizedStatement *s) { stop = true; }
+    };
+
+    UsesEH ueh;
+    return walkPostorder(this, &ueh);
+}
+
+/* ============================================== */
+// true if statement 'comes from' somewhere else, like a goto
+
+bool Statement::comeFrom()
+{
+    class ComeFrom : public StoppableVisitor
+    {
+    public:
+        void visit(Statement *s)        {}
+        void visit(CaseStatement *s)    { stop = true; }
+        void visit(DefaultStatement *s) { stop = true; }
+        void visit(LabelStatement *s)   { stop = true; }
+        void visit(AsmStatement *s)     { stop = true; }
+#ifdef IN_GCC
+        void visit(ExtAsmStatement *s)  { stop = true; }
+#endif
+    };
+
+    ComeFrom cf;
+    return walkPostorder(this, &cf);
+}
+
+/* ============================================== */
+// Return true if statement has executable code.
+
+bool Statement::hasCode()
+{
+    class HasCode : public StoppableVisitor
+    {
+    public:
+        void visit(Statement *s)
+        {
+            stop = true;
+        }
+
+        void visit(ExpStatement *s)
+        {
+            if (s->exp != NULL)
+            {
+                stop = s->exp->hasCode();
+            }
+        }
+
+        void visit(CompoundStatement *s) {}
+        void visit(ScopeStatement *s)    {}
+        void visit(ImportStatement *s)   {}
+    };
+
+    HasCode hc;
+    return walkPostorder(this, &hc);
+}
+
+Statement *Statement::last()
+{
+    return this;
+}
+
+/****************************************
+ * If this statement has code that needs to run in a finally clause
+ * at the end of the current scope, return that code in the form of
+ * a Statement.
+ * Output:
+ *      *sentry         code executed upon entry to the scope
+ *      *sexception     code executed upon exit from the scope via exception
+ *      *sfinally       code executed in finally block
+ */
+
+Statement *Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
+{
+    //printf("Statement::scopeCode()\n");
+    //print();
+    *sentry = NULL;
+    *sexception = NULL;
+    *sfinally = NULL;
+    return this;
+}
+
+/*********************************
+ * Flatten out the scope by presenting the statement
+ * as an array of statements.
+ * Returns NULL if no flattening necessary.
+ */
+
+Statements *Statement::flatten(Scope *sc)
+{
+    return NULL;
+}
+
+
+/******************************** ErrorStatement ***************************/
+
+ErrorStatement::ErrorStatement()
+    : Statement(Loc())
+{
+    assert(global.gaggedErrors || global.errors);
+}
+
+Statement *ErrorStatement::syntaxCopy()
+{
+    return this;
+}
+
+/******************************** PeelStatement ***************************/
+
+PeelStatement::PeelStatement(Statement *s)
+    : Statement(s->loc)
+{
+    this->s = s;
+}
+
+/******************************** ExpStatement ***************************/
+
+ExpStatement::ExpStatement(Loc loc, Expression *exp)
+    : Statement(loc)
+{
+    this->exp = exp;
+}
+
+ExpStatement::ExpStatement(Loc loc, Dsymbol *declaration)
+    : Statement(loc)
+{
+    this->exp = new DeclarationExp(loc, declaration);
+}
+
+ExpStatement *ExpStatement::create(Loc loc, Expression *exp)
+{
+    return new ExpStatement(loc, exp);
+}
+
+Statement *ExpStatement::syntaxCopy()
+{
+    return new ExpStatement(loc, exp ? exp->syntaxCopy() : NULL);
+}
+
+Statement *ExpStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
+{
+    //printf("ExpStatement::scopeCode()\n");
+    //print();
+
+    *sentry = NULL;
+    *sexception = NULL;
+    *sfinally = NULL;
+
+    if (exp)
+    {
+        if (exp->op == TOKdeclaration)
+        {
+            DeclarationExp *de = (DeclarationExp *)(exp);
+            VarDeclaration *v = de->declaration->isVarDeclaration();
+            if (v && !v->isDataseg())
+            {
+                if (v->needsScopeDtor())
+                {
+                    //printf("dtor is: "); v->edtor->print();
+                    *sfinally = new DtorExpStatement(loc, v->edtor, v);
+                    v->storage_class |= STCnodtor; // don't add in dtor again
+                }
+            }
+        }
+    }
+    return this;
+}
+
+/****************************************
+ * Convert TemplateMixin members (== Dsymbols) to Statements.
+ */
+Statement *toStatement(Dsymbol *s)
+{
+    class ToStmt : public Visitor
+    {
+    public:
+        Statement *result;
+
+        ToStmt()
+        {
+            this->result = NULL;
+        }
+
+        Statement *visitMembers(Loc loc, Dsymbols *a)
+        {
+            if (!a)
+                return NULL;
+
+            Statements *statements = new Statements();
+            for (size_t i = 0; i < a->dim; i++)
+            {
+                statements->push(toStatement((*a)[i]));
+            }
+            return new CompoundStatement(loc, statements);
+        }
+
+        void visit(Dsymbol *s)
+        {
+            ::error(Loc(), "Internal Compiler Error: cannot mixin %s %s\n", s->kind(), s->toChars());
+            result = new ErrorStatement();
+        }
+
+        void visit(TemplateMixin *tm)
+        {
+            Statements *a = new Statements();
+            for (size_t i = 0; i < tm->members->dim; i++)
+            {
+                Statement *s = toStatement((*tm->members)[i]);
+                if (s)
+                    a->push(s);
+            }
+            result = new CompoundStatement(tm->loc, a);
+        }
+
+        /* An actual declaration symbol will be converted to DeclarationExp
+         * with ExpStatement.
+         */
+        Statement *declStmt(Dsymbol *s)
+        {
+            DeclarationExp *de = new DeclarationExp(s->loc, s);
+            de->type = Type::tvoid;     // avoid repeated semantic
+            return new ExpStatement(s->loc, de);
+        }
+        void visit(VarDeclaration *d)       { result = declStmt(d); }
+        void visit(AggregateDeclaration *d) { result = declStmt(d); }
+        void visit(FuncDeclaration *d)      { result = declStmt(d); }
+        void visit(EnumDeclaration *d)      { result = declStmt(d); }
+        void visit(AliasDeclaration *d)     { result = declStmt(d); }
+        void visit(TemplateDeclaration *d)  { result = declStmt(d); }
+
+        /* All attributes have been already picked by the semantic analysis of
+         * 'bottom' declarations (function, struct, class, etc).
+         * So we don't have to copy them.
+         */
+        void visit(StorageClassDeclaration *d)  { result = visitMembers(d->loc, d->decl); }
+        void visit(DeprecatedDeclaration *d)    { result = visitMembers(d->loc, d->decl); }
+        void visit(LinkDeclaration *d)          { result = visitMembers(d->loc, d->decl); }
+        void visit(ProtDeclaration *d)          { result = visitMembers(d->loc, d->decl); }
+        void visit(AlignDeclaration *d)         { result = visitMembers(d->loc, d->decl); }
+        void visit(UserAttributeDeclaration *d) { result = visitMembers(d->loc, d->decl); }
+
+        void visit(StaticAssert *s) {}
+        void visit(Import *s) {}
+        void visit(PragmaDeclaration *d) {}
+
+        void visit(ConditionalDeclaration *d)
+        {
+            result = visitMembers(d->loc, d->include(NULL, NULL));
+        }
+
+        void visit(CompileDeclaration *d)
+        {
+            result = visitMembers(d->loc, d->include(NULL, NULL));
+        }
+    };
+
+    if (!s)
+        return NULL;
+
+    ToStmt v;
+    s->accept(&v);
+    return v.result;
+}
+
+Statements *ExpStatement::flatten(Scope *sc)
+{
+    /* Bugzilla 14243: expand template mixin in statement scope
+     * to handle variable destructors.
+     */
+    if (exp && exp->op == TOKdeclaration)
+    {
+        Dsymbol *d = ((DeclarationExp *)exp)->declaration;
+        if (TemplateMixin *tm = d->isTemplateMixin())
+        {
+            Expression *e = semantic(exp, sc);
+            if (e->op == TOKerror || tm->errors)
+            {
+                Statements *a = new Statements();
+                a->push(new ErrorStatement());
+                return a;
+            }
+            assert(tm->members);
+
+            Statement *s = toStatement(tm);
+        #if 0
+            OutBuffer buf;
+            buf.doindent = 1;
+            HdrGenState hgs;
+            hgs.hdrgen = true;
+            toCBuffer(s, &buf, &hgs);
+            printf("tm ==> s = %s\n", buf.peekString());
+        #endif
+            Statements *a = new Statements();
+            a->push(s);
+            return a;
+        }
+    }
+    return NULL;
+}
+
+/******************************** DtorExpStatement ***************************/
+
+DtorExpStatement::DtorExpStatement(Loc loc, Expression *exp, VarDeclaration *v)
+    : ExpStatement(loc, exp)
+{
+    this->var = v;
+}
+
+Statement *DtorExpStatement::syntaxCopy()
+{
+    return new DtorExpStatement(loc, exp ? exp->syntaxCopy() : NULL, var);
+}
+
+/******************************** CompileStatement ***************************/
+
+CompileStatement::CompileStatement(Loc loc, Expression *exp)
+    : Statement(loc)
+{
+    this->exp = exp;
+}
+
+Statement *CompileStatement::syntaxCopy()
+{
+    return new CompileStatement(loc, exp->syntaxCopy());
+}
+
+Statements *CompileStatement::flatten(Scope *sc)
+{
+    //printf("CompileStatement::flatten() %s\n", exp->toChars());
+    sc = sc->startCTFE();
+    exp = semantic(exp, sc);
+    exp = resolveProperties(sc, exp);
+    sc = sc->endCTFE();
+
+    Statements *a = new Statements();
+    if (exp->op != TOKerror)
+    {
+        Expression *e = exp->ctfeInterpret();
+        StringExp *se = e->toStringExp();
+        if (!se)
+           error("argument to mixin must be a string, not (%s) of type %s", exp->toChars(), exp->type->toChars());
+        else
+        {
+            se = se->toUTF8(sc);
+            unsigned errors = global.errors;
+            Parser p(loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+            p.nextToken();
+
+            while (p.token.value != TOKeof)
+            {
+                Statement *s = p.parseStatement(PSsemi | PScurlyscope);
+                if (!s || p.errors)
+                {
+                    assert(!p.errors || global.errors != errors); // make sure we caught all the cases
+                    goto Lerror;
+                }
+                a->push(s);
+            }
+            return a;
+        }
+    }
+Lerror:
+    a->push(new ErrorStatement());
+    return a;
+}
+
+/******************************** CompoundStatement ***************************/
+
+CompoundStatement::CompoundStatement(Loc loc, Statements *s)
+    : Statement(loc)
+{
+    statements = s;
+}
+
+CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2)
+    : Statement(loc)
+{
+    statements = new Statements();
+    statements->reserve(2);
+    statements->push(s1);
+    statements->push(s2);
+}
+
+CompoundStatement::CompoundStatement(Loc loc, Statement *s1)
+    : Statement(loc)
+{
+    statements = new Statements();
+    statements->push(s1);
+}
+
+CompoundStatement *CompoundStatement::create(Loc loc, Statement *s1, Statement *s2)
+{
+    return new CompoundStatement(loc, s1, s2);
+}
+
+Statement *CompoundStatement::syntaxCopy()
+{
+    Statements *a = new Statements();
+    a->setDim(statements->dim);
+    for (size_t i = 0; i < statements->dim; i++)
+    {
+        Statement *s = (*statements)[i];
+        (*a)[i] = s ? s->syntaxCopy() : NULL;
+    }
+    return new CompoundStatement(loc, a);
+}
+
+Statements *CompoundStatement::flatten(Scope *sc)
+{
+    return statements;
+}
+
+ReturnStatement *CompoundStatement::isReturnStatement()
+{
+    ReturnStatement *rs = NULL;
+
+    for (size_t i = 0; i < statements->dim; i++)
+    {
+        Statement *s = (*statements)[i];
+        if (s)
+        {
+            rs = s->isReturnStatement();
+            if (rs)
+                break;
+        }
+    }
+    return rs;
+}
+
+Statement *CompoundStatement::last()
+{
+    Statement *s = NULL;
+
+    for (size_t i = statements->dim; i; --i)
+    {   s = (*statements)[i - 1];
+        if (s)
+        {
+            s = s->last();
+            if (s)
+                break;
+        }
+    }
+    return s;
+}
+
+/******************************** CompoundDeclarationStatement ***************************/
+
+CompoundDeclarationStatement::CompoundDeclarationStatement(Loc loc, Statements *s)
+    : CompoundStatement(loc, s)
+{
+    statements = s;
+}
+
+Statement *CompoundDeclarationStatement::syntaxCopy()
+{
+    Statements *a = new Statements();
+    a->setDim(statements->dim);
+    for (size_t i = 0; i < statements->dim; i++)
+    {
+        Statement *s = (*statements)[i];
+        (*a)[i] = s ? s->syntaxCopy() : NULL;
+    }
+    return new CompoundDeclarationStatement(loc, a);
+}
+
+/**************************** UnrolledLoopStatement ***************************/
+
+UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s)
+    : Statement(loc)
+{
+    statements = s;
+}
+
+Statement *UnrolledLoopStatement::syntaxCopy()
+{
+    Statements *a = new Statements();
+    a->setDim(statements->dim);
+    for (size_t i = 0; i < statements->dim; i++)
+    {
+        Statement *s = (*statements)[i];
+        (*a)[i] = s ? s->syntaxCopy() : NULL;
+    }
+    return new UnrolledLoopStatement(loc, a);
+}
+
+bool UnrolledLoopStatement::hasBreak()
+{
+    return true;
+}
+
+bool UnrolledLoopStatement::hasContinue()
+{
+    return true;
+}
+
+/******************************** ScopeStatement ***************************/
+
+ScopeStatement::ScopeStatement(Loc loc, Statement *s, Loc endloc)
+    : Statement(loc)
+{
+    this->statement = s;
+    this->endloc = endloc;
+}
+
+Statement *ScopeStatement::syntaxCopy()
+{
+    return new ScopeStatement(loc, statement ? statement->syntaxCopy() : NULL, endloc);
+}
+
+ReturnStatement *ScopeStatement::isReturnStatement()
+{
+    if (statement)
+        return statement->isReturnStatement();
+    return NULL;
+}
+
+bool ScopeStatement::hasBreak()
+{
+    //printf("ScopeStatement::hasBreak() %s\n", toChars());
+    return statement ? statement->hasBreak() : false;
+}
+
+bool ScopeStatement::hasContinue()
+{
+    return statement ? statement->hasContinue() : false;
+}
+
+/******************************** WhileStatement ***************************/
+
+WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b, Loc endloc)
+    : Statement(loc)
+{
+    condition = c;
+    _body = b;
+    this->endloc = endloc;
+}
+
+Statement *WhileStatement::syntaxCopy()
+{
+    return new WhileStatement(loc,
+        condition->syntaxCopy(),
+        _body ? _body->syntaxCopy() : NULL,
+        endloc);
+}
+
+bool WhileStatement::hasBreak()
+{
+    return true;
+}
+
+bool WhileStatement::hasContinue()
+{
+    return true;
+}
+
+/******************************** DoStatement ***************************/
+
+DoStatement::DoStatement(Loc loc, Statement *b, Expression *c, Loc endloc)
+    : Statement(loc)
+{
+    _body = b;
+    condition = c;
+    this->endloc = endloc;
+}
+
+Statement *DoStatement::syntaxCopy()
+{
+    return new DoStatement(loc,
+        _body ? _body->syntaxCopy() : NULL,
+        condition->syntaxCopy(),
+        endloc);
+}
+
+bool DoStatement::hasBreak()
+{
+    return true;
+}
+
+bool DoStatement::hasContinue()
+{
+    return true;
+}
+
+/******************************** ForStatement ***************************/
+
+ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body, Loc endloc)
+    : Statement(loc)
+{
+    this->_init = init;
+    this->condition = condition;
+    this->increment = increment;
+    this->_body = body;
+    this->endloc = endloc;
+    this->relatedLabeled = NULL;
+}
+
+Statement *ForStatement::syntaxCopy()
+{
+    return new ForStatement(loc,
+        _init ? _init->syntaxCopy() : NULL,
+        condition ? condition->syntaxCopy() : NULL,
+        increment ? increment->syntaxCopy() : NULL,
+        _body->syntaxCopy(),
+        endloc);
+}
+
+Statement *ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
+{
+    //printf("ForStatement::scopeCode()\n");
+    Statement::scopeCode(sc, sentry, sexception, sfinally);
+    return this;
+}
+
+bool ForStatement::hasBreak()
+{
+    //printf("ForStatement::hasBreak()\n");
+    return true;
+}
+
+bool ForStatement::hasContinue()
+{
+    return true;
+}
+
+/******************************** ForeachStatement ***************************/
+
+ForeachStatement::ForeachStatement(Loc loc, TOK op, Parameters *parameters,
+        Expression *aggr, Statement *body, Loc endloc)
+    : Statement(loc)
+{
+    this->op = op;
+    this->parameters = parameters;
+    this->aggr = aggr;
+    this->_body = body;
+    this->endloc = endloc;
+
+    this->key = NULL;
+    this->value = NULL;
+
+    this->func = NULL;
+
+    this->cases = NULL;
+    this->gotos = NULL;
+}
+
+Statement *ForeachStatement::syntaxCopy()
+{
+    return new ForeachStatement(loc, op,
+        Parameter::arraySyntaxCopy(parameters),
+        aggr->syntaxCopy(),
+        _body ? _body->syntaxCopy() : NULL,
+        endloc);
+}
+
+bool ForeachStatement::checkForArgTypes()
+{
+    bool result = false;
+
+    for (size_t i = 0; i < parameters->dim; i++)
+    {
+        Parameter *p = (*parameters)[i];
+        if (!p->type)
+        {
+            error("cannot infer type for %s", p->ident->toChars());
+            p->type = Type::terror;
+            result = true;
+        }
+    }
+    return result;
+}
+
+bool ForeachStatement::hasBreak()
+{
+    return true;
+}
+
+bool ForeachStatement::hasContinue()
+{
+    return true;
+}
+
+/**************************** ForeachRangeStatement ***************************/
+
+
+ForeachRangeStatement::ForeachRangeStatement(Loc loc, TOK op, Parameter *prm,
+        Expression *lwr, Expression *upr, Statement *body, Loc endloc)
+    : Statement(loc)
+{
+    this->op = op;
+    this->prm = prm;
+    this->lwr = lwr;
+    this->upr = upr;
+    this->_body = body;
+    this->endloc = endloc;
+
+    this->key = NULL;
+}
+
+Statement *ForeachRangeStatement::syntaxCopy()
+{
+    return new ForeachRangeStatement(loc, op,
+        prm->syntaxCopy(),
+        lwr->syntaxCopy(),
+        upr->syntaxCopy(),
+        _body ? _body->syntaxCopy() : NULL,
+        endloc);
+}
+
+bool ForeachRangeStatement::hasBreak()
+{
+    return true;
+}
+
+bool ForeachRangeStatement::hasContinue()
+{
+    return true;
+}
+
+/******************************** IfStatement ***************************/
+
+IfStatement::IfStatement(Loc loc, Parameter *prm, Expression *condition, Statement *ifbody, Statement *elsebody, Loc endloc)
+    : Statement(loc)
+{
+    this->prm = prm;
+    this->condition = condition;
+    this->ifbody = ifbody;
+    this->elsebody = elsebody;
+    this->endloc = endloc;
+    this->match = NULL;
+}
+
+Statement *IfStatement::syntaxCopy()
+{
+    return new IfStatement(loc,
+        prm ? prm->syntaxCopy() : NULL,
+        condition->syntaxCopy(),
+        ifbody ? ifbody->syntaxCopy() : NULL,
+        elsebody ? elsebody->syntaxCopy() : NULL,
+        endloc);
+}
+
+/******************************** ConditionalStatement ***************************/
+
+ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody)
+    : Statement(loc)
+{
+    this->condition = condition;
+    this->ifbody = ifbody;
+    this->elsebody = elsebody;
+}
+
+Statement *ConditionalStatement::syntaxCopy()
+{
+    return new ConditionalStatement(loc,
+        condition->syntaxCopy(),
+        ifbody->syntaxCopy(),
+        elsebody ? elsebody->syntaxCopy() : NULL);
+}
+
+Statements *ConditionalStatement::flatten(Scope *sc)
+{
+    Statement *s;
+
+    //printf("ConditionalStatement::flatten()\n");
+    if (condition->include(sc, NULL))
+    {
+        DebugCondition *dc = condition->isDebugCondition();
+        if (dc)
+            s = new DebugStatement(loc, ifbody);
+        else
+            s = ifbody;
+    }
+    else
+        s = elsebody;
+
+    Statements *a = new Statements();
+    a->push(s);
+    return a;
+}
+
+/******************************** PragmaStatement ***************************/
+
+PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
+    : Statement(loc)
+{
+    this->ident = ident;
+    this->args = args;
+    this->_body = body;
+}
+
+Statement *PragmaStatement::syntaxCopy()
+{
+    return new PragmaStatement(loc, ident,
+        Expression::arraySyntaxCopy(args),
+        _body ? _body->syntaxCopy() : NULL);
+}
+
+/******************************** StaticAssertStatement ***************************/
+
+StaticAssertStatement::StaticAssertStatement(StaticAssert *sa)
+    : Statement(sa->loc)
+{
+    this->sa = sa;
+}
+
+Statement *StaticAssertStatement::syntaxCopy()
+{
+    return new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL));
+}
+
+/******************************** SwitchStatement ***************************/
+
+SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal)
+    : Statement(loc)
+{
+    this->condition = c;
+    this->_body = b;
+    this->isFinal = isFinal;
+    sdefault = NULL;
+    tf = NULL;
+    cases = NULL;
+    hasNoDefault = 0;
+    hasVars = 0;
+}
+
+Statement *SwitchStatement::syntaxCopy()
+{
+    return new SwitchStatement(loc,
+        condition->syntaxCopy(),
+        _body->syntaxCopy(),
+        isFinal);
+}
+
+bool SwitchStatement::hasBreak()
+{
+    return true;
+}
+
+static bool checkVar(SwitchStatement *s, VarDeclaration *vd)
+{
+    if (!vd || vd->isDataseg() || (vd->storage_class & STCmanifest))
+        return false;
+
+    VarDeclaration *last = s->lastVar;
+    while (last && last != vd)
+        last = last->lastVar;
+    if (last == vd)
+    {
+        // All good, the label's scope has no variables
+    }
+    else if (vd->storage_class & STCexptemp)
+    {
+        // Lifetime ends at end of expression, so no issue with skipping the statement
+    }
+    else if (vd->ident == Id::withSym)
+    {
+        s->deprecation("'switch' skips declaration of 'with' temporary at %s", vd->loc.toChars());
+        return true;
+    }
+    else
+    {
+        s->deprecation("'switch' skips declaration of variable %s at %s", vd->toPrettyChars(), vd->loc.toChars());
+        return true;
+    }
+
+    return false;
+}
+
+bool SwitchStatement::checkLabel()
+{
+    const bool error = true;
+
+    if (sdefault && checkVar(this, sdefault->lastVar))
+        return !error; // return error once fully deprecated
+
+    for (size_t i = 0; i < cases->dim; i++)
+    {
+        CaseStatement *scase = (*cases)[i];
+        if (scase && checkVar(this, scase->lastVar))
+            return !error; // return error once fully deprecated
+    }
+    return !error;
+}
+
+/******************************** CaseStatement ***************************/
+
+CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
+    : Statement(loc)
+{
+    this->exp = exp;
+    this->statement = s;
+    index = 0;
+}
+
+Statement *CaseStatement::syntaxCopy()
+{
+    return new CaseStatement(loc,
+        exp->syntaxCopy(),
+        statement->syntaxCopy());
+}
+
+int CaseStatement::compare(RootObject *obj)
+{
+    // Sort cases so we can do an efficient lookup
+    CaseStatement *cs2 = (CaseStatement *)(obj);
+
+    return exp->compare(cs2->exp);
+}
+
+/******************************** CaseRangeStatement ***************************/
+
+
+CaseRangeStatement::CaseRangeStatement(Loc loc, Expression *first,
+        Expression *last, Statement *s)
+    : Statement(loc)
+{
+    this->first = first;
+    this->last = last;
+    this->statement = s;
+}
+
+Statement *CaseRangeStatement::syntaxCopy()
+{
+    return new CaseRangeStatement(loc,
+        first->syntaxCopy(),
+        last->syntaxCopy(),
+        statement->syntaxCopy());
+}
+
+/******************************** DefaultStatement ***************************/
+
+DefaultStatement::DefaultStatement(Loc loc, Statement *s)
+    : Statement(loc)
+{
+    this->statement = s;
+}
+
+Statement *DefaultStatement::syntaxCopy()
+{
+    return new DefaultStatement(loc, statement->syntaxCopy());
+}
+
+/******************************** GotoDefaultStatement ***************************/
+
+GotoDefaultStatement::GotoDefaultStatement(Loc loc)
+    : Statement(loc)
+{
+    sw = NULL;
+}
+
+Statement *GotoDefaultStatement::syntaxCopy()
+{
+    return new GotoDefaultStatement(loc);
+}
+
+/******************************** GotoCaseStatement ***************************/
+
+GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp)
+    : Statement(loc)
+{
+    cs = NULL;
+    this->exp = exp;
+}
+
+Statement *GotoCaseStatement::syntaxCopy()
+{
+    return new GotoCaseStatement(loc, exp ? exp->syntaxCopy() : NULL);
+}
+
+/******************************** SwitchErrorStatement ***************************/
+
+SwitchErrorStatement::SwitchErrorStatement(Loc loc)
+    : Statement(loc)
+{
+}
+
+/******************************** ReturnStatement ***************************/
+
+ReturnStatement::ReturnStatement(Loc loc, Expression *exp)
+    : Statement(loc)
+{
+    this->exp = exp;
+    this->caseDim = 0;
+}
+
+Statement *ReturnStatement::syntaxCopy()
+{
+    return new ReturnStatement(loc, exp ? exp->syntaxCopy() : NULL);
+}
+
+/******************************** BreakStatement ***************************/
+
+BreakStatement::BreakStatement(Loc loc, Identifier *ident)
+    : Statement(loc)
+{
+    this->ident = ident;
+}
+
+Statement *BreakStatement::syntaxCopy()
+{
+    return new BreakStatement(loc, ident);
+}
+
+/******************************** ContinueStatement ***************************/
+
+ContinueStatement::ContinueStatement(Loc loc, Identifier *ident)
+    : Statement(loc)
+{
+    this->ident = ident;
+}
+
+Statement *ContinueStatement::syntaxCopy()
+{
+    return new ContinueStatement(loc, ident);
+}
+
+/******************************** SynchronizedStatement ***************************/
+
+SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body)
+    : Statement(loc)
+{
+    this->exp = exp;
+    this->_body = body;
+}
+
+Statement *SynchronizedStatement::syntaxCopy()
+{
+    return new SynchronizedStatement(loc,
+        exp ? exp->syntaxCopy() : NULL,
+        _body ? _body->syntaxCopy() : NULL);
+}
+
+bool SynchronizedStatement::hasBreak()
+{
+    return false; //true;
+}
+
+bool SynchronizedStatement::hasContinue()
+{
+    return false; //true;
+}
+
+/******************************** WithStatement ***************************/
+
+WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body, Loc endloc)
+    : Statement(loc)
+{
+    this->exp = exp;
+    this->_body = body;
+    this->endloc = endloc;
+    wthis = NULL;
+}
+
+Statement *WithStatement::syntaxCopy()
+{
+    return new WithStatement(loc,
+        exp->syntaxCopy(),
+        _body ? _body->syntaxCopy() : NULL, endloc);
+}
+
+/******************************** TryCatchStatement ***************************/
+
+TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Catches *catches)
+    : Statement(loc)
+{
+    this->_body = body;
+    this->catches = catches;
+}
+
+Statement *TryCatchStatement::syntaxCopy()
+{
+    Catches *a = new Catches();
+    a->setDim(catches->dim);
+    for (size_t i = 0; i < a->dim; i++)
+    {
+        Catch *c = (*catches)[i];
+        (*a)[i] = c->syntaxCopy();
+    }
+    return new TryCatchStatement(loc, _body->syntaxCopy(), a);
+}
+
+bool TryCatchStatement::hasBreak()
+{
+    return false;
+}
+
+/******************************** Catch ***************************/
+
+Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
+{
+    //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
+    this->loc = loc;
+    this->type = t;
+    this->ident = id;
+    this->handler = handler;
+    var = NULL;
+    errors = false;
+    internalCatch = false;
+}
+
+Catch *Catch::syntaxCopy()
+{
+    Catch *c = new Catch(loc,
+        type ? type->syntaxCopy() : NULL,
+        ident,
+        (handler ? handler->syntaxCopy() : NULL));
+    c->internalCatch = internalCatch;
+    return c;
+}
+
+/****************************** TryFinallyStatement ***************************/
+
+TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody)
+    : Statement(loc)
+{
+    this->_body = body;
+    this->finalbody = finalbody;
+}
+
+TryFinallyStatement *TryFinallyStatement::create(Loc loc, Statement *body, Statement *finalbody)
+{
+    return new TryFinallyStatement(loc, body, finalbody);
+}
+
+Statement *TryFinallyStatement::syntaxCopy()
+{
+    return new TryFinallyStatement(loc,
+        _body->syntaxCopy(), finalbody->syntaxCopy());
+}
+
+bool TryFinallyStatement::hasBreak()
+{
+    return false; //true;
+}
+
+bool TryFinallyStatement::hasContinue()
+{
+    return false; //true;
+}
+
+/****************************** OnScopeStatement ***************************/
+
+OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement)
+    : Statement(loc)
+{
+    this->tok = tok;
+    this->statement = statement;
+}
+
+Statement *OnScopeStatement::syntaxCopy()
+{
+    return new OnScopeStatement(loc, tok, statement->syntaxCopy());
+}
+
+Statement *OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
+{
+    //printf("OnScopeStatement::scopeCode()\n");
+    //print();
+    *sentry = NULL;
+    *sexception = NULL;
+    *sfinally = NULL;
+
+    Statement *s = new PeelStatement(statement);
+
+    switch (tok)
+    {
+        case TOKon_scope_exit:
+            *sfinally = s;
+            break;
+
+        case TOKon_scope_failure:
+            *sexception = s;
+            break;
+
+        case TOKon_scope_success:
+        {
+            /* Create:
+             *  sentry:   bool x = false;
+             *  sexception:    x = true;
+             *  sfinally: if (!x) statement;
+             */
+            VarDeclaration *v = copyToTemp(0, "__os", new IntegerExp(Loc(), 0, Type::tbool));
+            *sentry = new ExpStatement(loc, v);
+
+            Expression *e = new IntegerExp(Loc(), 1, Type::tbool);
+            e = new AssignExp(Loc(), new VarExp(Loc(), v), e);
+            *sexception = new ExpStatement(Loc(), e);
+
+            e = new VarExp(Loc(), v);
+            e = new NotExp(Loc(), e);
+            *sfinally = new IfStatement(Loc(), NULL, e, s, NULL, Loc());
+
+            break;
+        }
+
+        default:
+            assert(0);
+    }
+    return NULL;
+}
+
+/******************************** ThrowStatement ***************************/
+
+ThrowStatement::ThrowStatement(Loc loc, Expression *exp)
+    : Statement(loc)
+{
+    this->exp = exp;
+    this->internalThrow = false;
+}
+
+Statement *ThrowStatement::syntaxCopy()
+{
+    ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy());
+    s->internalThrow = internalThrow;
+    return s;
+}
+
+/******************************** DebugStatement **************************/
+
+DebugStatement::DebugStatement(Loc loc, Statement *statement)
+    : Statement(loc)
+{
+    this->statement = statement;
+}
+
+Statement *DebugStatement::syntaxCopy()
+{
+    return new DebugStatement(loc,
+        statement ? statement->syntaxCopy() : NULL);
+}
+
+Statements *DebugStatement::flatten(Scope *sc)
+{
+    Statements *a = statement ? statement->flatten(sc) : NULL;
+    if (a)
+    {
+        for (size_t i = 0; i < a->dim; i++)
+        {   Statement *s = (*a)[i];
+
+            s = new DebugStatement(loc, s);
+            (*a)[i] = s;
+        }
+    }
+
+    return a;
+}
+
+/******************************** GotoStatement ***************************/
+
+GotoStatement::GotoStatement(Loc loc, Identifier *ident)
+    : Statement(loc)
+{
+    this->ident = ident;
+    this->label = NULL;
+    this->tf = NULL;
+    this->os = NULL;
+    this->lastVar = NULL;
+}
+
+Statement *GotoStatement::syntaxCopy()
+{
+    return new GotoStatement(loc, ident);
+}
+
+bool GotoStatement::checkLabel()
+{
+    if (!label->statement)
+    {
+        error("label '%s' is undefined", label->toChars());
+        return true;
+    }
+
+    if (label->statement->os != os)
+    {
+        if (os && os->tok == TOKon_scope_failure && !label->statement->os)
+        {
+            // Jump out from scope(failure) block is allowed.
+        }
+        else
+        {
+            if (label->statement->os)
+                error("cannot goto in to %s block", Token::toChars(label->statement->os->tok));
+            else
+                error("cannot goto out of %s block", Token::toChars(os->tok));
+            return true;
+        }
+    }
+
+    if (label->statement->tf != tf)
+    {
+        error("cannot goto in or out of finally block");
+        return true;
+    }
+
+    VarDeclaration *vd = label->statement->lastVar;
+    if (!vd || vd->isDataseg() || (vd->storage_class & STCmanifest))
+        return false;
+
+    VarDeclaration *last = lastVar;
+    while (last && last != vd)
+        last = last->lastVar;
+    if (last == vd)
+    {
+        // All good, the label's scope has no variables
+    }
+    else if (vd->ident == Id::withSym)
+    {
+        error("goto skips declaration of with temporary at %s", vd->loc.toChars());
+        return true;
+    }
+    else
+    {
+        error("goto skips declaration of variable %s at %s", vd->toPrettyChars(), vd->loc.toChars());
+        return true;
+    }
+
+    return false;
+}
+
+/******************************** LabelStatement ***************************/
+
+LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
+    : Statement(loc)
+{
+    this->ident = ident;
+    this->statement = statement;
+    this->tf = NULL;
+    this->os = NULL;
+    this->lastVar = NULL;
+    this->gotoTarget = NULL;
+    this->breaks = false;
+}
+
+Statement *LabelStatement::syntaxCopy()
+{
+    return new LabelStatement(loc, ident, statement ? statement->syntaxCopy() : NULL);
+}
+
+Statement *LabelStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally)
+{
+    //printf("LabelStatement::scopeCode()\n");
+    if (statement)
+        statement = statement->scopeCode(sc, sentry, sexit, sfinally);
+    else
+    {
+        *sentry = NULL;
+        *sexit = NULL;
+        *sfinally = NULL;
+    }
+    return this;
+}
+
+Statements *LabelStatement::flatten(Scope *sc)
+{
+    Statements *a = NULL;
+
+    if (statement)
+    {
+        a = statement->flatten(sc);
+        if (a)
+        {
+            if (!a->dim)
+            {
+                a->push(new ExpStatement(loc, (Expression *)NULL));
+            }
+
+            // reuse 'this' LabelStatement
+            this->statement = (*a)[0];
+            (*a)[0] = this;
+        }
+    }
+
+    return a;
+}
+
+/******************************** LabelDsymbol ***************************/
+
+LabelDsymbol::LabelDsymbol(Identifier *ident)
+        : Dsymbol(ident)
+{
+    statement = NULL;
+}
+
+LabelDsymbol *LabelDsymbol::create(Identifier *ident)
+{
+    return new LabelDsymbol(ident);
+}
+
+LabelDsymbol *LabelDsymbol::isLabel()           // is this a LabelDsymbol()?
+{
+    return this;
+}
+
+
+/************************ AsmStatement ***************************************/
+
+AsmStatement::AsmStatement(Loc loc, Token *tokens)
+    : Statement(loc)
+{
+    this->tokens = tokens;
+    asmcode = NULL;
+    asmalign = 0;
+    refparam = false;
+    naked = false;
+    regs = 0;
+}
+
+Statement *AsmStatement::syntaxCopy()
+{
+    return new AsmStatement(loc, tokens);
+}
+
+
+#ifdef IN_GCC
+/************************ ExtAsmStatement ***************************************/
+
+ExtAsmStatement::ExtAsmStatement(Loc loc, StorageClass stc, Expression *insn,
+                                 Expressions *args, Identifiers *names,
+                                 Expressions *constraints, int outputargs,
+                                 Expressions *clobbers, Identifiers *labels)
+        : Statement(loc)
+{
+    this->stc = stc;
+    this->insn = insn;
+    this->args = args;
+    this->names = names;
+    this->constraints = constraints;
+    this->outputargs = outputargs;
+    this->clobbers = clobbers;
+    this->labels = labels;
+    this->gotos = NULL;
+}
+
+Statement *ExtAsmStatement::syntaxCopy()
+{
+    Expressions *c_args = Expression::arraySyntaxCopy(args);
+    Expressions *c_constraints = Expression::arraySyntaxCopy(constraints);
+    Expressions *c_clobbers = Expression::arraySyntaxCopy(clobbers);
+
+    return new ExtAsmStatement(loc, stc, insn->syntaxCopy(), c_args, names,
+                               c_constraints, outputargs, c_clobbers, labels);
+}
+
+#endif
+
+/************************ CompoundAsmStatement ***************************************/
+
+CompoundAsmStatement::CompoundAsmStatement(Loc loc, Statements *s, StorageClass stc)
+    : CompoundStatement(loc, s)
+{
+    this->stc = stc;
+}
+
+CompoundAsmStatement *CompoundAsmStatement::syntaxCopy()
+{
+    Statements *a = new Statements();
+    a->setDim(statements->dim);
+    for (size_t i = 0; i < statements->dim; i++)
+    {
+        Statement *s = (*statements)[i];
+        (*a)[i] = s ? s->syntaxCopy() : NULL;
+    }
+    return new CompoundAsmStatement(loc, a, stc);
+}
+
+Statements *CompoundAsmStatement::flatten(Scope *sc)
+{
+    return NULL;
+}
+
+/************************ ImportStatement ***************************************/
+
+ImportStatement::ImportStatement(Loc loc, Dsymbols *imports)
+    : Statement(loc)
+{
+    this->imports = imports;
+}
+
+Statement *ImportStatement::syntaxCopy()
+{
+    Dsymbols *m = new Dsymbols();
+    m->setDim(imports->dim);
+    for (size_t i = 0; i < imports->dim; i++)
+    {
+        Dsymbol *s = (*imports)[i];
+        (*m)[i] = s->syntaxCopy(NULL);
+    }
+    return new ImportStatement(loc, m);
+}
diff --git a/gcc/d/dfrontend/statement.h b/gcc/d/dfrontend/statement.h
new file mode 100644
index 00000000000..6c306a10a2a
--- /dev/null
+++ b/gcc/d/dfrontend/statement.h
@@ -0,0 +1,784 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/statement.h
+ */
+
+#ifndef DMD_STATEMENT_H
+#define DMD_STATEMENT_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+
+#include "arraytypes.h"
+#include "dsymbol.h"
+#include "visitor.h"
+#include "tokens.h"
+
+struct OutBuffer;
+struct Scope;
+class Expression;
+class LabelDsymbol;
+class Identifier;
+class IfStatement;
+class ExpStatement;
+class DefaultStatement;
+class VarDeclaration;
+class Condition;
+class Module;
+struct Token;
+class ErrorStatement;
+class ReturnStatement;
+class CompoundStatement;
+class Parameter;
+class StaticAssert;
+class AsmStatement;
+class GotoStatement;
+class ScopeStatement;
+class TryCatchStatement;
+class TryFinallyStatement;
+class CaseStatement;
+class DefaultStatement;
+class LabelStatement;
+class StaticForeach;
+
+// Back end
+struct code;
+
+bool inferAggregate(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply);
+bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply);
+
+/* How a statement exits; this is returned by blockExit()
+ */
+enum BE
+{
+    BEnone =     0,
+    BEfallthru = 1,
+    BEthrow =    2,
+    BEreturn =   4,
+    BEgoto =     8,
+    BEhalt =     0x10,
+    BEbreak =    0x20,
+    BEcontinue = 0x40,
+    BEerrthrow = 0x80,
+    BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt),
+};
+
+class Statement : public RootObject
+{
+public:
+    Loc loc;
+
+    Statement(Loc loc);
+    virtual Statement *syntaxCopy();
+
+    void print();
+    const char *toChars();
+
+    void error(const char *format, ...);
+    void warning(const char *format, ...);
+    void deprecation(const char *format, ...);
+    virtual Statement *getRelatedLabeled() { return this; }
+    virtual bool hasBreak();
+    virtual bool hasContinue();
+    bool usesEH();
+    bool comeFrom();
+    bool hasCode();
+    virtual Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
+    virtual Statements *flatten(Scope *sc);
+    virtual Statement *last();
+
+    // Avoid dynamic_cast
+    virtual ErrorStatement *isErrorStatement() { return NULL; }
+    virtual ScopeStatement *isScopeStatement() { return NULL; }
+    virtual ExpStatement *isExpStatement() { return NULL; }
+    virtual CompoundStatement *isCompoundStatement() { return NULL; }
+    virtual ReturnStatement *isReturnStatement() { return NULL; }
+    virtual IfStatement *isIfStatement() { return NULL; }
+    virtual CaseStatement *isCaseStatement() { return NULL; }
+    virtual DefaultStatement *isDefaultStatement() { return NULL; }
+    virtual LabelStatement *isLabelStatement() { return NULL; }
+    virtual GotoDefaultStatement *isGotoDefaultStatement() { return NULL; }
+    virtual GotoCaseStatement *isGotoCaseStatement() { return NULL; }
+    virtual BreakStatement *isBreakStatement() { return NULL; }
+    virtual DtorExpStatement *isDtorExpStatement() { return NULL; }
+    virtual ForwardingStatement *isForwardingStatement() { return NULL; }
+    virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+/** Any Statement that fails semantic() or has a component that is an ErrorExp or
+ * a TypeError should return an ErrorStatement from semantic().
+ */
+class ErrorStatement : public Statement
+{
+public:
+    ErrorStatement();
+    Statement *syntaxCopy();
+
+    ErrorStatement *isErrorStatement() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class PeelStatement : public Statement
+{
+public:
+    Statement *s;
+
+    PeelStatement(Statement *s);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ExpStatement : public Statement
+{
+public:
+    Expression *exp;
+
+    ExpStatement(Loc loc, Expression *exp);
+    ExpStatement(Loc loc, Dsymbol *s);
+    static ExpStatement *create(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
+    Statements *flatten(Scope *sc);
+
+    ExpStatement *isExpStatement() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DtorExpStatement : public ExpStatement
+{
+public:
+    /* Wraps an expression that is the destruction of 'var'
+     */
+
+    VarDeclaration *var;
+
+    DtorExpStatement(Loc loc, Expression *exp, VarDeclaration *v);
+    Statement *syntaxCopy();
+    void accept(Visitor *v) { v->visit(this); }
+
+    DtorExpStatement *isDtorExpStatement() { return this; }
+};
+
+class CompileStatement : public Statement
+{
+public:
+    Expression *exp;
+
+    CompileStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    Statements *flatten(Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class CompoundStatement : public Statement
+{
+public:
+    Statements *statements;
+
+    CompoundStatement(Loc loc, Statements *s);
+    CompoundStatement(Loc loc, Statement *s1);
+    CompoundStatement(Loc loc, Statement *s1, Statement *s2);
+    static CompoundStatement *create(Loc loc, Statement *s1, Statement *s2);
+    Statement *syntaxCopy();
+    Statements *flatten(Scope *sc);
+    ReturnStatement *isReturnStatement();
+    Statement *last();
+
+    CompoundStatement *isCompoundStatement() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class CompoundDeclarationStatement : public CompoundStatement
+{
+public:
+    CompoundDeclarationStatement(Loc loc, Statements *s);
+    Statement *syntaxCopy();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/* The purpose of this is so that continue will go to the next
+ * of the statements, and break will go to the end of the statements.
+ */
+class UnrolledLoopStatement : public Statement
+{
+public:
+    Statements *statements;
+
+    UnrolledLoopStatement(Loc loc, Statements *statements);
+    Statement *syntaxCopy();
+    bool hasBreak();
+    bool hasContinue();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ScopeStatement : public Statement
+{
+public:
+    Statement *statement;
+    Loc endloc;                 // location of closing curly bracket
+
+    ScopeStatement(Loc loc, Statement *s, Loc endloc);
+    Statement *syntaxCopy();
+    ScopeStatement *isScopeStatement() { return this; }
+    ReturnStatement *isReturnStatement();
+    bool hasBreak();
+    bool hasContinue();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ForwardingStatement : public Statement
+{
+    Statement *statement;
+    ForwardingScopeDsymbol *sym;
+
+    ForwardingStatement *isForwardingStatement() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class WhileStatement : public Statement
+{
+public:
+    Expression *condition;
+    Statement *_body;
+    Loc endloc;                 // location of closing curly bracket
+
+    WhileStatement(Loc loc, Expression *c, Statement *b, Loc endloc);
+    Statement *syntaxCopy();
+    bool hasBreak();
+    bool hasContinue();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DoStatement : public Statement
+{
+public:
+    Statement *_body;
+    Expression *condition;
+    Loc endloc;                 // location of ';' after while
+
+    DoStatement(Loc loc, Statement *b, Expression *c, Loc endloc);
+    Statement *syntaxCopy();
+    bool hasBreak();
+    bool hasContinue();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ForStatement : public Statement
+{
+public:
+    Statement *_init;
+    Expression *condition;
+    Expression *increment;
+    Statement *_body;
+    Loc endloc;                 // location of closing curly bracket
+
+    // When wrapped in try/finally clauses, this points to the outermost one,
+    // which may have an associated label. Internal break/continue statements
+    // treat that label as referring to this loop.
+    Statement *relatedLabeled;
+
+    ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body, Loc endloc);
+    Statement *syntaxCopy();
+    Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
+    Statement *getRelatedLabeled() { return relatedLabeled ? relatedLabeled : this; }
+    bool hasBreak();
+    bool hasContinue();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ForeachStatement : public Statement
+{
+public:
+    TOK op;                     // TOKforeach or TOKforeach_reverse
+    Parameters *parameters;     // array of Parameter*'s
+    Expression *aggr;
+    Statement *_body;
+    Loc endloc;                 // location of closing curly bracket
+
+    VarDeclaration *key;
+    VarDeclaration *value;
+
+    FuncDeclaration *func;      // function we're lexically in
+
+    Statements *cases;          // put breaks, continues, gotos and returns here
+    ScopeStatements *gotos;     // forward referenced goto's go here
+
+    ForeachStatement(Loc loc, TOK op, Parameters *parameters, Expression *aggr, Statement *body, Loc endloc);
+    Statement *syntaxCopy();
+    bool checkForArgTypes();
+    bool hasBreak();
+    bool hasContinue();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ForeachRangeStatement : public Statement
+{
+public:
+    TOK op;                     // TOKforeach or TOKforeach_reverse
+    Parameter *prm;             // loop index variable
+    Expression *lwr;
+    Expression *upr;
+    Statement *_body;
+    Loc endloc;                 // location of closing curly bracket
+
+    VarDeclaration *key;
+
+    ForeachRangeStatement(Loc loc, TOK op, Parameter *prm,
+        Expression *lwr, Expression *upr, Statement *body, Loc endloc);
+    Statement *syntaxCopy();
+    bool hasBreak();
+    bool hasContinue();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class IfStatement : public Statement
+{
+public:
+    Parameter *prm;
+    Expression *condition;
+    Statement *ifbody;
+    Statement *elsebody;
+    Loc endloc;                 // location of closing curly bracket
+
+    VarDeclaration *match;      // for MatchExpression results
+
+    IfStatement(Loc loc, Parameter *prm, Expression *condition, Statement *ifbody, Statement *elsebody, Loc endloc);
+    Statement *syntaxCopy();
+    IfStatement *isIfStatement() { return this; }
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ConditionalStatement : public Statement
+{
+public:
+    Condition *condition;
+    Statement *ifbody;
+    Statement *elsebody;
+
+    ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody);
+    Statement *syntaxCopy();
+    Statements *flatten(Scope *sc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticForeachStatement : public Statement
+{
+public:
+    StaticForeach *sfe;
+
+    Statement *syntaxCopy();
+    Statements *flatten(Scope *sc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class PragmaStatement : public Statement
+{
+public:
+    Identifier *ident;
+    Expressions *args;          // array of Expression's
+    Statement *_body;
+
+    PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body);
+    Statement *syntaxCopy();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticAssertStatement : public Statement
+{
+public:
+    StaticAssert *sa;
+
+    StaticAssertStatement(StaticAssert *sa);
+    Statement *syntaxCopy();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class SwitchStatement : public Statement
+{
+public:
+    Expression *condition;
+    Statement *_body;
+    bool isFinal;
+
+    DefaultStatement *sdefault;
+    TryFinallyStatement *tf;
+    GotoCaseStatements gotoCases;  // array of unresolved GotoCaseStatement's
+    CaseStatements *cases;         // array of CaseStatement's
+    int hasNoDefault;           // !=0 if no default statement
+    int hasVars;                // !=0 if has variable case values
+    VarDeclaration *lastVar;
+
+    SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal);
+    Statement *syntaxCopy();
+    bool hasBreak();
+    bool checkLabel();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class CaseStatement : public Statement
+{
+public:
+    Expression *exp;
+    Statement *statement;
+
+    int index;          // which case it is (since we sort this)
+    VarDeclaration *lastVar;
+
+    CaseStatement(Loc loc, Expression *exp, Statement *s);
+    Statement *syntaxCopy();
+    int compare(RootObject *obj);
+    CaseStatement *isCaseStatement() { return this; }
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+
+class CaseRangeStatement : public Statement
+{
+public:
+    Expression *first;
+    Expression *last;
+    Statement *statement;
+
+    CaseRangeStatement(Loc loc, Expression *first, Expression *last, Statement *s);
+    Statement *syntaxCopy();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+
+class DefaultStatement : public Statement
+{
+public:
+    Statement *statement;
+    VarDeclaration *lastVar;
+
+    DefaultStatement(Loc loc, Statement *s);
+    Statement *syntaxCopy();
+    DefaultStatement *isDefaultStatement() { return this; }
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class GotoDefaultStatement : public Statement
+{
+public:
+    SwitchStatement *sw;
+
+    GotoDefaultStatement(Loc loc);
+    Statement *syntaxCopy();
+    GotoDefaultStatement *isGotoDefaultStatement() { return this; }
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class GotoCaseStatement : public Statement
+{
+public:
+    Expression *exp;            // NULL, or which case to goto
+    CaseStatement *cs;          // case statement it resolves to
+
+    GotoCaseStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    GotoCaseStatement *isGotoCaseStatement() { return this; }
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class SwitchErrorStatement : public Statement
+{
+public:
+    SwitchErrorStatement(Loc loc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ReturnStatement : public Statement
+{
+public:
+    Expression *exp;
+    size_t caseDim;
+
+    ReturnStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+
+    ReturnStatement *isReturnStatement() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class BreakStatement : public Statement
+{
+public:
+    Identifier *ident;
+
+    BreakStatement(Loc loc, Identifier *ident);
+    Statement *syntaxCopy();
+
+    BreakStatement *isBreakStatement() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ContinueStatement : public Statement
+{
+public:
+    Identifier *ident;
+
+    ContinueStatement(Loc loc, Identifier *ident);
+    Statement *syntaxCopy();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class SynchronizedStatement : public Statement
+{
+public:
+    Expression *exp;
+    Statement *_body;
+
+    SynchronizedStatement(Loc loc, Expression *exp, Statement *body);
+    Statement *syntaxCopy();
+    bool hasBreak();
+    bool hasContinue();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class WithStatement : public Statement
+{
+public:
+    Expression *exp;
+    Statement *_body;
+    VarDeclaration *wthis;
+    Loc endloc;
+
+    WithStatement(Loc loc, Expression *exp, Statement *body, Loc endloc);
+    Statement *syntaxCopy();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TryCatchStatement : public Statement
+{
+public:
+    Statement *_body;
+    Catches *catches;
+
+    TryCatchStatement(Loc loc, Statement *body, Catches *catches);
+    Statement *syntaxCopy();
+    bool hasBreak();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class Catch : public RootObject
+{
+public:
+    Loc loc;
+    Type *type;
+    Identifier *ident;
+    VarDeclaration *var;
+    Statement *handler;
+
+    // set if semantic processing errors
+    bool errors;
+
+    // was generated by the compiler,
+    // wasn't present in source code
+    bool internalCatch;
+
+    Catch(Loc loc, Type *t, Identifier *id, Statement *handler);
+    Catch *syntaxCopy();
+};
+
+class TryFinallyStatement : public Statement
+{
+public:
+    Statement *_body;
+    Statement *finalbody;
+
+    TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody);
+    static TryFinallyStatement *create(Loc loc, Statement *body, Statement *finalbody);
+    Statement *syntaxCopy();
+    bool hasBreak();
+    bool hasContinue();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class OnScopeStatement : public Statement
+{
+public:
+    TOK tok;
+    Statement *statement;
+
+    OnScopeStatement(Loc loc, TOK tok, Statement *statement);
+    Statement *syntaxCopy();
+    Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ThrowStatement : public Statement
+{
+public:
+    Expression *exp;
+    // was generated by the compiler,
+    // wasn't present in source code
+    bool internalThrow;
+
+    ThrowStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class DebugStatement : public Statement
+{
+public:
+    Statement *statement;
+
+    DebugStatement(Loc loc, Statement *statement);
+    Statement *syntaxCopy();
+    Statements *flatten(Scope *sc);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class GotoStatement : public Statement
+{
+public:
+    Identifier *ident;
+    LabelDsymbol *label;
+    TryFinallyStatement *tf;
+    OnScopeStatement *os;
+    VarDeclaration *lastVar;
+
+    GotoStatement(Loc loc, Identifier *ident);
+    Statement *syntaxCopy();
+    bool checkLabel();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class LabelStatement : public Statement
+{
+public:
+    Identifier *ident;
+    Statement *statement;
+    TryFinallyStatement *tf;
+    OnScopeStatement *os;
+    VarDeclaration *lastVar;
+    Statement *gotoTarget;      // interpret
+
+    bool breaks;                // someone did a 'break ident'
+
+    LabelStatement(Loc loc, Identifier *ident, Statement *statement);
+    Statement *syntaxCopy();
+    Statements *flatten(Scope *sc);
+    Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
+
+    LabelStatement *isLabelStatement() { return this; }
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class LabelDsymbol : public Dsymbol
+{
+public:
+    LabelStatement *statement;
+
+    LabelDsymbol(Identifier *ident);
+    static LabelDsymbol *create(Identifier *ident);
+    LabelDsymbol *isLabel();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+Statement* asmSemantic(AsmStatement *s, Scope *sc);
+
+class AsmStatement : public Statement
+{
+public:
+    Token *tokens;
+    code *asmcode;
+    unsigned asmalign;          // alignment of this statement
+    unsigned regs;              // mask of registers modified (must match regm_t in back end)
+    bool refparam;              // true if function parameter is referenced
+    bool naked;                 // true if function is to be naked
+
+    AsmStatement(Loc loc, Token *tokens);
+    Statement *syntaxCopy();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+// a complete asm {} block
+class CompoundAsmStatement : public CompoundStatement
+{
+public:
+    StorageClass stc; // postfix attributes like nothrow/pure/@trusted
+
+    CompoundAsmStatement(Loc loc, Statements *s, StorageClass stc);
+    CompoundAsmStatement *syntaxCopy();
+    Statements *flatten(Scope *sc);
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class ImportStatement : public Statement
+{
+public:
+    Dsymbols *imports;          // Array of Import's
+
+    ImportStatement(Loc loc, Dsymbols *imports);
+    Statement *syntaxCopy();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#ifdef IN_GCC
+
+// Assembler instructions with D expression operands
+class ExtAsmStatement : public Statement
+{
+public:
+    StorageClass stc;
+    Expression *insn;
+    Expressions *args;
+    Identifiers *names;
+    Expressions *constraints;   // Array of StringExp's
+    unsigned outputargs;
+    Expressions *clobbers;      // Array of StringExp's
+    Identifiers *labels;
+    GotoStatements *gotos;
+
+    ExtAsmStatement(Loc loc, StorageClass stc, Expression *insn,
+                    Expressions *args, Identifiers *names,
+                    Expressions *constraints, int outputargs,
+                    Expressions *clobbers, Identifiers *labels);
+    Statement *syntaxCopy();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#endif
+
+#endif /* DMD_STATEMENT_H */
diff --git a/gcc/d/dfrontend/statementsem.c b/gcc/d/dfrontend/statementsem.c
new file mode 100644
index 00000000000..8d088661976
--- /dev/null
+++ b/gcc/d/dfrontend/statementsem.c
@@ -0,0 +1,3630 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "rmem.h"
+#include "checkedint.h"
+
+#include "statement.h"
+#include "expression.h"
+#include "cond.h"
+#include "init.h"
+#include "staticassert.h"
+#include "module.h"
+#include "scope.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+#include "enum.h"
+#include "template.h"
+#include "import.h"
+#include "target.h"
+#include "visitor.h"
+
+StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f);
+bool checkEscapeRef(Scope *sc, Expression *e, bool gag);
+LabelStatement *checkLabeledLoop(Scope *sc, Statement *statement);
+Identifier *fixupLabelName(Scope *sc, Identifier *ident);
+FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
+VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
+Expression *checkAssignmentAsCondition(Expression *e);
+
+Expression *semantic(Expression *e, Scope *sc);
+Statement *semantic(Statement *s, Scope *sc);
+void semantic(Catch *c, Scope *sc);
+Statement *semanticNoScope(Statement *s, Scope *sc);
+Statement *semanticScope(Statement *s, Scope *sc, Statement *sbreak, Statement *scontinue);
+int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow);
+
+class StatementSemanticVisitor : public Visitor
+{
+public:
+    Statement *result;
+    Scope *sc;
+
+    StatementSemanticVisitor(Scope *sc)
+    {
+        this->result = NULL;
+        this->sc = sc;
+    }
+
+private:
+    void setError()
+    {
+        result = new ErrorStatement();
+    }
+
+public:
+    void visit(Statement *s)
+    {
+        result = s;
+    }
+
+    void visit(ErrorStatement *s)
+    {
+        result = s;
+    }
+
+    void visit(PeelStatement *s)
+    {
+        /* "peel" off this wrapper, and don't run semantic()
+         * on the result.
+         */
+        result = s->s;
+    }
+
+    void visit(ExpStatement *s)
+    {
+        if (s->exp)
+        {
+            //printf("ExpStatement::semantic() %s\n", s->exp->toChars());
+
+            // Allow CommaExp in ExpStatement because return isn't used
+            if (s->exp->op == TOKcomma)
+                ((CommaExp *)s->exp)->allowCommaExp = true;
+
+            s->exp = semantic(s->exp, sc);
+            s->exp = resolveProperties(sc, s->exp);
+            s->exp = s->exp->addDtorHook(sc);
+            if (FuncDeclaration *f = isFuncAddress(s->exp))
+            {
+                if (f->checkForwardRef(s->exp->loc))
+                    s->exp = new ErrorExp();
+            }
+            if (discardValue(s->exp))
+                s->exp = new ErrorExp();
+
+            s->exp = s->exp->optimize(WANTvalue);
+            s->exp = checkGC(sc, s->exp);
+            if (s->exp->op == TOKerror)
+                return setError();
+        }
+        result = s;
+    }
+
+    void visit(CompileStatement *cs)
+    {
+        //printf("CompileStatement::semantic() %s\n", cs->exp->toChars());
+        Statements *a = cs->flatten(sc);
+        if (!a)
+            return;
+        Statement *s = new CompoundStatement(cs->loc, a);
+        result = semantic(s, sc);
+    }
+
+    void visit(CompoundStatement *cs)
+    {
+        //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", cs, sc);
+
+#if 0
+        for (size_t i = 0; i < cs->statements->dim; i++)
+        {
+            Statement *s = (*cs->statements)[i];
+            if (s)
+                printf("[%d]: %s", i, s->toChars());
+        }
+#endif
+
+        for (size_t i = 0; i < cs->statements->dim; )
+        {
+            Statement *s = (*cs->statements)[i];
+            if (s)
+            {
+                Statements *flt = s->flatten(sc);
+                if (flt)
+                {
+                    cs->statements->remove(i);
+                    cs->statements->insert(i, flt);
+                    continue;
+                }
+                s = semantic(s, sc);
+                (*cs->statements)[i] = s;
+                if (s)
+                {
+                    Statement *sentry;
+                    Statement *sexception;
+                    Statement *sfinally;
+
+                    (*cs->statements)[i] = s->scopeCode(sc, &sentry, &sexception, &sfinally);
+                    if (sentry)
+                    {
+                        sentry = semantic(sentry, sc);
+                        cs->statements->insert(i, sentry);
+                        i++;
+                    }
+                    if (sexception)
+                        sexception = semantic(sexception, sc);
+                    if (sexception)
+                    {
+                        if (i + 1 == cs->statements->dim && !sfinally)
+                        {
+                        }
+                        else
+                        {
+                            /* Rewrite:
+                             *      s; s1; s2;
+                             * As:
+                             *      s;
+                             *      try { s1; s2; }
+                             *      catch (Throwable __o)
+                             *      { sexception; throw __o; }
+                             */
+                            Statements *a = new Statements();
+                            for (size_t j = i + 1; j < cs->statements->dim; j++)
+                            {
+                                a->push((*cs->statements)[j]);
+                            }
+                            Statement *body = new CompoundStatement(Loc(), a);
+                            body = new ScopeStatement(Loc(), body, Loc());
+
+                            Identifier *id = Identifier::generateId("__o");
+
+                            Statement *handler = new PeelStatement(sexception);
+                            if (blockExit(sexception, sc->func, false) & BEfallthru)
+                            {
+                                ThrowStatement *ts = new ThrowStatement(Loc(), new IdentifierExp(Loc(), id));
+                                ts->internalThrow = true;
+                                handler = new CompoundStatement(Loc(), handler, ts);
+                            }
+
+                            Catches *catches = new Catches();
+                            Catch *ctch = new Catch(Loc(), NULL, id, handler);
+                            ctch->internalCatch = true;
+                            catches->push(ctch);
+
+                            s = new TryCatchStatement(Loc(), body, catches);
+                            if (sfinally)
+                                s = new TryFinallyStatement(Loc(), s, sfinally);
+                            s = semantic(s, sc);
+
+                            cs->statements->setDim(i + 1);
+                            cs->statements->push(s);
+                            break;
+                        }
+                    }
+                    else if (sfinally)
+                    {
+                        if (0 && i + 1 == cs->statements->dim)
+                        {
+                            cs->statements->push(sfinally);
+                        }
+                        else
+                        {
+                            /* Rewrite:
+                             *      s; s1; s2;
+                             * As:
+                             *      s; try { s1; s2; } finally { sfinally; }
+                             */
+                            Statements *a = new Statements();
+                            for (size_t j = i + 1; j < cs->statements->dim; j++)
+                            {
+                                a->push((*cs->statements)[j]);
+                            }
+                            Statement *body = new CompoundStatement(Loc(), a);
+                            s = new TryFinallyStatement(Loc(), body, sfinally);
+                            s = semantic(s, sc);
+                            cs->statements->setDim(i + 1);
+                            cs->statements->push(s);
+                            break;
+                        }
+                    }
+                }
+                else
+                {
+                    /* Remove NULL statements from the list.
+                    */
+                    cs->statements->remove(i);
+                    continue;
+                }
+            }
+            i++;
+        }
+        for (size_t i = 0; i < cs->statements->dim; ++i)
+        {
+        Lagain:
+            Statement *s = (*cs->statements)[i];
+            if (!s)
+                continue;
+
+            Statement *se = s->isErrorStatement();
+            if (se)
+            {
+                result = se;
+                return;
+            }
+
+            /* Bugzilla 11653: 'semantic' may return another CompoundStatement
+             * (eg. CaseRangeStatement), so flatten it here.
+             */
+            Statements *flt = s->flatten(sc);
+            if (flt)
+            {
+                cs->statements->remove(i);
+                cs->statements->insert(i, flt);
+                if (cs->statements->dim <= i)
+                    break;
+                goto Lagain;
+            }
+        }
+        if (cs->statements->dim == 1)
+        {
+            result = (*cs->statements)[0];
+            return;
+        }
+        result = cs;
+    }
+
+    void visit(UnrolledLoopStatement *uls)
+    {
+        //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", uls, sc);
+        Scope *scd = sc->push();
+        scd->sbreak = uls;
+        scd->scontinue = uls;
+
+        Statement *serror = NULL;
+        for (size_t i = 0; i < uls->statements->dim; i++)
+        {
+            Statement *s = (*uls->statements)[i];
+            if (s)
+            {
+                //printf("[%d]: %s\n", i, s->toChars());
+                s = semantic(s, scd);
+                (*uls->statements)[i] = s;
+
+                if (s && !serror)
+                    serror = s->isErrorStatement();
+            }
+        }
+
+        scd->pop();
+        result = serror ? serror : uls;
+    }
+
+    void visit(ScopeStatement *ss)
+    {
+        ScopeDsymbol *sym;
+        //printf("ScopeStatement::semantic(sc = %p)\n", sc);
+        if (ss->statement)
+        {
+            sym = new ScopeDsymbol();
+            sym->parent = sc->scopesym;
+            sym->endlinnum = ss->endloc.linnum;
+            sc = sc->push(sym);
+
+            Statements *a = ss->statement->flatten(sc);
+            if (a)
+            {
+                ss->statement = new CompoundStatement(ss->loc, a);
+            }
+
+            ss->statement = semantic(ss->statement, sc);
+            if (ss->statement)
+            {
+                if (ss->statement->isErrorStatement())
+                {
+                    sc->pop();
+                    result = ss->statement;
+                    return;
+                }
+
+                Statement *sentry;
+                Statement *sexception;
+                Statement *sfinally;
+
+                ss->statement = ss->statement->scopeCode(sc, &sentry, &sexception, &sfinally);
+                assert(!sentry);
+                assert(!sexception);
+                if (sfinally)
+                {
+                    //printf("adding sfinally\n");
+                    sfinally = semantic(sfinally, sc);
+                    ss->statement = new CompoundStatement(ss->loc, ss->statement, sfinally);
+                }
+            }
+
+            sc->pop();
+        }
+        result = ss;
+    }
+
+    void visit(WhileStatement *ws)
+    {
+        /* Rewrite as a for(;condition;) loop
+         */
+        Statement *s = new ForStatement(ws->loc, NULL, ws->condition, NULL, ws->_body, ws->endloc);
+        s = semantic(s, sc);
+        result = s;
+    }
+
+    void visit(DoStatement *ds)
+    {
+        sc->noctor++;
+        if (ds->_body)
+            ds->_body = semanticScope(ds->_body, sc, ds, ds);
+        sc->noctor--;
+
+        if (ds->condition->op == TOKdotid)
+            ((DotIdExp *)ds->condition)->noderef = true;
+
+        // check in syntax level
+        ds->condition = checkAssignmentAsCondition(ds->condition);
+
+        ds->condition = semantic(ds->condition, sc);
+        ds->condition = resolveProperties(sc, ds->condition);
+        ds->condition = ds->condition->optimize(WANTvalue);
+        ds->condition = checkGC(sc, ds->condition);
+
+        ds->condition = ds->condition->toBoolean(sc);
+
+        if (ds->condition->op == TOKerror)
+            return setError();
+
+        if (ds->_body && ds->_body->isErrorStatement())
+        {
+            result = ds->_body;
+            return;
+        }
+
+        result = ds;
+    }
+
+    void visit(ForStatement *fs)
+    {
+        //printf("ForStatement::semantic %s\n", toChars());
+
+        if (fs->_init)
+        {
+            /* Rewrite:
+             *  for (auto v1 = i1, v2 = i2; condition; increment) { ... }
+             * to:
+             *  { auto v1 = i1, v2 = i2; for (; condition; increment) { ... } }
+             * then lowered to:
+             *  auto v1 = i1;
+             *  try {
+             *    auto v2 = i2;
+             *    try {
+             *      for (; condition; increment) { ... }
+             *    } finally { v2.~this(); }
+             *  } finally { v1.~this(); }
+             */
+            Statements *ainit = new Statements();
+            ainit->push(fs->_init);
+            fs->_init = NULL;
+            ainit->push(fs);
+            Statement *s = new CompoundStatement(fs->loc, ainit);
+            s = new ScopeStatement(fs->loc, s, fs->endloc);
+            s = semantic(s, sc);
+            if (!s->isErrorStatement())
+            {
+                if (LabelStatement *ls = checkLabeledLoop(sc, fs))
+                    ls->gotoTarget = fs;
+                fs->relatedLabeled = s;
+            }
+            result = s;
+            return;
+        }
+        assert(fs->_init == NULL);
+
+        ScopeDsymbol *sym = new ScopeDsymbol();
+        sym->parent = sc->scopesym;
+        sym->endlinnum = fs->endloc.linnum;
+        sc = sc->push(sym);
+
+        sc->noctor++;
+        if (fs->condition)
+        {
+            if (fs->condition->op == TOKdotid)
+                ((DotIdExp *)fs->condition)->noderef = true;
+
+            // check in syntax level
+            fs->condition = checkAssignmentAsCondition(fs->condition);
+
+            fs->condition = semantic(fs->condition, sc);
+            fs->condition = resolveProperties(sc, fs->condition);
+            fs->condition = fs->condition->optimize(WANTvalue);
+            fs->condition = checkGC(sc, fs->condition);
+            fs->condition = fs->condition->toBoolean(sc);
+        }
+        if (fs->increment)
+        {
+            if (fs->increment->op == TOKcomma)
+                ((CommaExp *)fs->increment)->allowCommaExp = true;
+            fs->increment = semantic(fs->increment, sc);
+            fs->increment = resolveProperties(sc, fs->increment);
+            fs->increment = fs->increment->optimize(WANTvalue);
+            fs->increment = checkGC(sc, fs->increment);
+        }
+
+        sc->sbreak = fs;
+        sc->scontinue = fs;
+        if (fs->_body)
+            fs->_body = semanticNoScope(fs->_body, sc);
+        sc->noctor--;
+
+        sc->pop();
+
+        if (fs->condition && fs->condition->op == TOKerror ||
+            fs->increment && fs->increment->op == TOKerror ||
+            fs->_body && fs->_body->isErrorStatement())
+            return setError();
+
+        result = fs;
+    }
+
+    void visit(ForeachStatement *fs)
+    {
+        //printf("ForeachStatement::semantic() %p\n", fs);
+        ScopeDsymbol *sym;
+        Statement *s = fs;
+        Loc loc = fs->loc;
+        size_t dim = fs->parameters->dim;
+        TypeAArray *taa = NULL;
+        Dsymbol *sapply = NULL;
+
+        Type *tn = NULL;
+        Type *tnv = NULL;
+
+        fs->func = sc->func;
+        if (fs->func->fes)
+            fs->func = fs->func->fes->func;
+
+        VarDeclaration *vinit = NULL;
+        fs->aggr = semantic(fs->aggr, sc);
+        fs->aggr = resolveProperties(sc, fs->aggr);
+        fs->aggr = fs->aggr->optimize(WANTvalue);
+        if (fs->aggr->op == TOKerror)
+            return setError();
+
+        Expression *oaggr = fs->aggr;
+        if (fs->aggr->type && fs->aggr->type->toBasetype()->ty == Tstruct &&
+            ((TypeStruct *)(fs->aggr->type->toBasetype()))->sym->dtor &&
+            fs->aggr->op != TOKtype && !fs->aggr->isLvalue())
+        {
+            // Bugzilla 14653: Extend the life of rvalue aggregate till the end of foreach.
+            vinit = copyToTemp(STCrvalue, "__aggr", fs->aggr);
+            vinit->semantic(sc);
+            fs->aggr = new VarExp(fs->aggr->loc, vinit);
+        }
+
+        if (!inferAggregate(fs, sc, sapply))
+        {
+            const char *msg = "";
+            if (fs->aggr->type && isAggregate(fs->aggr->type))
+            {
+                msg = ", define opApply(), range primitives, or use .tupleof";
+            }
+            fs->error("invalid foreach aggregate %s%s", oaggr->toChars(), msg);
+            return setError();
+        }
+
+        Dsymbol* sapplyOld = sapply;  // 'sapply' will be NULL if and after 'inferApplyArgTypes' errors
+
+        /* Check for inference errors
+        */
+        if (!inferApplyArgTypes(fs, sc, sapply))
+        {
+            /**
+              Try and extract the parameter count of the opApply callback function, e.g.:
+              int opApply(int delegate(int, float)) => 2 args
+              */
+            bool foundMismatch = false;
+            size_t foreachParamCount = 0;
+            if (sapplyOld)
+            {
+                if (FuncDeclaration *fd = sapplyOld->isFuncDeclaration())
+                {
+                    int fvarargs;  // ignored (opApply shouldn't take variadics)
+                    Parameters *fparameters = fd->getParameters(&fvarargs);
+
+                    if (Parameter::dim(fparameters) == 1)
+                    {
+                        // first param should be the callback function
+                        Parameter *fparam = Parameter::getNth(fparameters, 0);
+                        if ((fparam->type->ty == Tpointer || fparam->type->ty == Tdelegate) &&
+                            fparam->type->nextOf()->ty == Tfunction)
+                        {
+                            TypeFunction *tf = (TypeFunction *)fparam->type->nextOf();
+                            foreachParamCount = Parameter::dim(tf->parameters);
+                            foundMismatch = true;
+                        }
+                    }
+                }
+            }
+
+            //printf("dim = %d, parameters->dim = %d\n", dim, fs->parameters->dim);
+            if (foundMismatch && dim != foreachParamCount)
+            {
+                const char *plural = foreachParamCount > 1 ? "s" : "";
+                fs->error("cannot infer argument types, expected %d argument%s, not %d",
+                          foreachParamCount, plural, dim);
+            }
+            else
+                fs->error("cannot uniquely infer foreach argument types");
+
+            return setError();
+        }
+
+        Type *tab = fs->aggr->type->toBasetype();
+
+        if (tab->ty == Ttuple)      // don't generate new scope for tuple loops
+        {
+            if (dim < 1 || dim > 2)
+            {
+                fs->error("only one (value) or two (key,value) arguments for tuple foreach");
+                return setError();
+            }
+
+            Type *paramtype = (*fs->parameters)[dim-1]->type;
+            if (paramtype)
+            {
+                paramtype = paramtype->semantic(loc, sc);
+                if (paramtype->ty == Terror)
+                    return setError();
+            }
+
+            TypeTuple *tuple = (TypeTuple *)tab;
+            Statements *statements = new Statements();
+            //printf("aggr: op = %d, %s\n", fs->aggr->op, fs->aggr->toChars());
+            size_t n;
+            TupleExp *te = NULL;
+            if (fs->aggr->op == TOKtuple)       // expression tuple
+            {
+                te = (TupleExp *)fs->aggr;
+                n = te->exps->dim;
+            }
+            else if (fs->aggr->op == TOKtype)   // type tuple
+            {
+                n = Parameter::dim(tuple->arguments);
+            }
+            else
+                assert(0);
+            for (size_t j = 0; j < n; j++)
+            {
+                size_t k = (fs->op == TOKforeach) ? j : n - 1 - j;
+                Expression *e = NULL;
+                Type *t = NULL;
+                if (te)
+                    e = (*te->exps)[k];
+                else
+                    t = Parameter::getNth(tuple->arguments, k)->type;
+                Parameter *p = (*fs->parameters)[0];
+                Statements *st = new Statements();
+
+                if (dim == 2)
+                {
+                    // Declare key
+                    if (p->storageClass & (STCout | STCref | STClazy))
+                    {
+                        fs->error("no storage class for key %s", p->ident->toChars());
+                        return setError();
+                    }
+                    p->type = p->type->semantic(loc, sc);
+                    TY keyty = p->type->ty;
+                    if (keyty != Tint32 && keyty != Tuns32)
+                    {
+                        if (global.params.isLP64)
+                        {
+                            if (keyty != Tint64 && keyty != Tuns64)
+                            {
+                                fs->error("foreach: key type must be int or uint, long or ulong, not %s", p->type->toChars());
+                                return setError();
+                            }
+                        }
+                        else
+                        {
+                            fs->error("foreach: key type must be int or uint, not %s", p->type->toChars());
+                            return setError();
+                        }
+                    }
+                    Initializer *ie = new ExpInitializer(Loc(), new IntegerExp(k));
+                    VarDeclaration *var = new VarDeclaration(loc, p->type, p->ident, ie);
+                    var->storage_class |= STCmanifest;
+                    st->push(new ExpStatement(loc, var));
+                    p = (*fs->parameters)[1];  // value
+                }
+                // Declare value
+                if (p->storageClass & (STCout | STClazy) ||
+                    p->storageClass & STCref && !te)
+                {
+                    fs->error("no storage class for value %s", p->ident->toChars());
+                    return setError();
+                }
+                Dsymbol *var;
+                if (te)
+                {
+                    Type *tb = e->type->toBasetype();
+                    Dsymbol *ds = NULL;
+                    if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar)
+                        ds = ((VarExp *)e)->var;
+                    else if (e->op == TOKtemplate)
+                        ds = ((TemplateExp *)e)->td;
+                    else if (e->op == TOKscope)
+                        ds = ((ScopeExp *)e)->sds;
+                    else if (e->op == TOKfunction)
+                    {
+                        FuncExp *fe = (FuncExp *)e;
+                        ds = fe->td ? (Dsymbol *)fe->td : fe->fd;
+                    }
+
+                    if (ds)
+                    {
+                        var = new AliasDeclaration(loc, p->ident, ds);
+                        if (p->storageClass & STCref)
+                        {
+                            fs->error("symbol %s cannot be ref", s->toChars());
+                            return setError();
+                        }
+                        if (paramtype)
+                        {
+                            fs->error("cannot specify element type for symbol %s", ds->toChars());
+                            return setError();
+                        }
+                    }
+                    else if (e->op == TOKtype)
+                    {
+                        var = new AliasDeclaration(loc, p->ident, e->type);
+                        if (paramtype)
+                        {
+                            fs->error("cannot specify element type for type %s", e->type->toChars());
+                            return setError();
+                        }
+                    }
+                    else
+                    {
+                        p->type = e->type;
+                        if (paramtype)
+                            p->type = paramtype;
+                        Initializer *ie = new ExpInitializer(Loc(), e);
+                        VarDeclaration *v = new VarDeclaration(loc, p->type, p->ident, ie);
+                        if (p->storageClass & STCref)
+                            v->storage_class |= STCref | STCforeach;
+                        if (e->isConst() || e->op == TOKstring ||
+                            e->op == TOKstructliteral || e->op == TOKarrayliteral)
+                        {
+                            if (v->storage_class & STCref)
+                            {
+                                fs->error("constant value %s cannot be ref", ie->toChars());
+                                return setError();
+                            }
+                            else
+                                v->storage_class |= STCmanifest;
+                        }
+                        var = v;
+                    }
+                }
+                else
+                {
+                    var = new AliasDeclaration(loc, p->ident, t);
+                    if (paramtype)
+                    {
+                        fs->error("cannot specify element type for symbol %s", s->toChars());
+                        return setError();
+                    }
+                }
+                st->push(new ExpStatement(loc, var));
+
+                st->push(fs->_body->syntaxCopy());
+                s = new CompoundStatement(loc, st);
+                s = new ScopeStatement(loc, s, fs->endloc);
+                statements->push(s);
+            }
+
+            s = new UnrolledLoopStatement(loc, statements);
+            if (LabelStatement *ls = checkLabeledLoop(sc, fs))
+                ls->gotoTarget = s;
+            if (te && te->e0)
+                s = new CompoundStatement(loc, new ExpStatement(te->e0->loc, te->e0), s);
+            if (vinit)
+                s = new CompoundStatement(loc, new ExpStatement(loc, vinit), s);
+            s = semantic(s, sc);
+            result = s;
+            return;
+        }
+
+        sym = new ScopeDsymbol();
+        sym->parent = sc->scopesym;
+        sym->endlinnum = fs->endloc.linnum;
+        sc = sc->push(sym);
+
+        sc->noctor++;
+
+        switch (tab->ty)
+        {
+            case Tarray:
+            case Tsarray:
+                {
+                    if (fs->checkForArgTypes())
+                    {
+                        result = fs;
+                        return;
+                    }
+
+                    if (dim < 1 || dim > 2)
+                    {
+                        fs->error("only one or two arguments for array foreach");
+                        goto Lerror2;
+                    }
+
+                    /* Look for special case of parsing char types out of char type
+                     * array.
+                     */
+                    tn = tab->nextOf()->toBasetype();
+                    if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
+                    {
+                        int i = (dim == 1) ? 0 : 1;     // index of value
+                        Parameter *p = (*fs->parameters)[i];
+                        p->type = p->type->semantic(loc, sc);
+                        p->type = p->type->addStorageClass(p->storageClass);
+                        tnv = p->type->toBasetype();
+                        if (tnv->ty != tn->ty &&
+                            (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar))
+                        {
+                            if (p->storageClass & STCref)
+                            {
+                                fs->error("foreach: value of UTF conversion cannot be ref");
+                                goto Lerror2;
+                            }
+                            if (dim == 2)
+                            {
+                                p = (*fs->parameters)[0];
+                                if (p->storageClass & STCref)
+                                {
+                                    fs->error("foreach: key cannot be ref");
+                                    goto Lerror2;
+                                }
+                            }
+                            goto Lapply;
+                        }
+                    }
+
+                    for (size_t i = 0; i < dim; i++)
+                    {
+                        // Declare parameterss
+                        Parameter *p = (*fs->parameters)[i];
+                        p->type = p->type->semantic(loc, sc);
+                        p->type = p->type->addStorageClass(p->storageClass);
+                        VarDeclaration *var;
+
+                        if (dim == 2 && i == 0)
+                        {
+                            var = new VarDeclaration(loc, p->type->mutableOf(), Identifier::generateId("__key"), NULL);
+                            var->storage_class |= STCtemp | STCforeach;
+                            if (var->storage_class & (STCref | STCout))
+                                var->storage_class |= STCnodtor;
+
+                            fs->key = var;
+                            if (p->storageClass & STCref)
+                            {
+                                if (var->type->constConv(p->type) <= MATCHnomatch)
+                                {
+                                    fs->error("key type mismatch, %s to ref %s",
+                                              var->type->toChars(), p->type->toChars());
+                                    goto Lerror2;
+                                }
+                            }
+                            if (tab->ty == Tsarray)
+                            {
+                                TypeSArray *ta =  (TypeSArray *)tab;
+                                IntRange dimrange = getIntRange(ta->dim);
+                                if (!IntRange::fromType(var->type).contains(dimrange))
+                                {
+                                    fs->error("index type '%s' cannot cover index range 0..%llu", p->type->toChars(), ta->dim->toInteger());
+                                    goto Lerror2;
+                                }
+                                fs->key->range = new IntRange(SignExtendedNumber(0), dimrange.imax);
+                            }
+                        }
+                        else
+                        {
+                            var = new VarDeclaration(loc, p->type, p->ident, NULL);
+                            var->storage_class |= STCforeach;
+                            var->storage_class |= p->storageClass & (STCin | STCout | STCref | STC_TYPECTOR);
+                            if (var->storage_class & (STCref | STCout))
+                                var->storage_class |= STCnodtor;
+
+                            fs->value = var;
+                            if (var->storage_class & STCref)
+                            {
+                                if (fs->aggr->checkModifiable(sc, 1) == 2)
+                                    var->storage_class |= STCctorinit;
+
+                                Type *t = tab->nextOf();
+                                if (t->constConv(p->type) <= MATCHnomatch)
+                                {
+                                    fs->error("argument type mismatch, %s to ref %s",
+                                              t->toChars(), p->type->toChars());
+                                    goto Lerror2;
+                                }
+                            }
+                        }
+                    }
+
+                    /* Convert to a ForStatement
+                     *   foreach (key, value; a) body =>
+                     *   for (T[] tmp = a[], size_t key; key < tmp.length; ++key)
+                     *   { T value = tmp[k]; body }
+                     *
+                     *   foreach_reverse (key, value; a) body =>
+                     *   for (T[] tmp = a[], size_t key = tmp.length; key--; )
+                     *   { T value = tmp[k]; body }
+                     */
+                    Identifier *id = Identifier::generateId("__r");
+                    ExpInitializer *ie = new ExpInitializer(loc, new SliceExp(loc, fs->aggr, NULL, NULL));
+                    VarDeclaration *tmp;
+                    if (fs->aggr->op == TOKarrayliteral &&
+                        !((*fs->parameters)[dim - 1]->storageClass & STCref))
+                    {
+                        ArrayLiteralExp *ale = (ArrayLiteralExp *)fs->aggr;
+                        size_t edim = ale->elements ? ale->elements->dim : 0;
+                        fs->aggr->type = tab->nextOf()->sarrayOf(edim);
+
+                        // for (T[edim] tmp = a, ...)
+                        tmp = new VarDeclaration(loc, fs->aggr->type, id, ie);
+                    }
+                    else
+                        tmp = new VarDeclaration(loc, tab->nextOf()->arrayOf(), id, ie);
+                    tmp->storage_class |= STCtemp;
+                    tmp->endlinnum = fs->endloc.linnum;
+
+                    Expression *tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id::length);
+
+                    if (!fs->key)
+                    {
+                        Identifier *idkey = Identifier::generateId("__key");
+                        fs->key = new VarDeclaration(loc, Type::tsize_t, idkey, NULL);
+                        fs->key->storage_class |= STCtemp;
+                    }
+                    if (fs->op == TOKforeach_reverse)
+                        fs->key->_init = new ExpInitializer(loc, tmp_length);
+                    else
+                        fs->key->_init = new ExpInitializer(loc, new IntegerExp(loc, 0, fs->key->type));
+
+                    Statements *cs = new Statements();
+                    if (vinit)
+                        cs->push(new ExpStatement(loc, vinit));
+                    cs->push(new ExpStatement(loc, tmp));
+                    cs->push(new ExpStatement(loc, fs->key));
+                    Statement *forinit = new CompoundDeclarationStatement(loc, cs);
+
+                    Expression *cond;
+                    if (fs->op == TOKforeach_reverse)
+                    {
+                        // key--
+                        cond = new PostExp(TOKminusminus, loc, new VarExp(loc, fs->key));
+                    }
+                    else
+                    {
+                        // key < tmp.length
+                        cond = new CmpExp(TOKlt, loc, new VarExp(loc, fs->key), tmp_length);
+                    }
+
+                    Expression *increment = NULL;
+                    if (fs->op == TOKforeach)
+                    {
+                        // key += 1
+                        increment = new AddAssignExp(loc, new VarExp(loc, fs->key), new IntegerExp(loc, 1, fs->key->type));
+                    }
+
+                    // T value = tmp[key];
+                    fs->value->_init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, fs->key)));
+                    Statement *ds = new ExpStatement(loc, fs->value);
+
+                    if (dim == 2)
+                    {
+                        Parameter *p = (*fs->parameters)[0];
+                        if ((p->storageClass & STCref) && p->type->equals(fs->key->type))
+                        {
+                            fs->key->range = NULL;
+                            AliasDeclaration *v = new AliasDeclaration(loc, p->ident, fs->key);
+                            fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
+                        }
+                        else
+                        {
+                            ExpInitializer *ei = new ExpInitializer(loc, new IdentifierExp(loc, fs->key->ident));
+                            VarDeclaration *v = new VarDeclaration(loc, p->type, p->ident, ei);
+                            v->storage_class |= STCforeach | (p->storageClass & STCref);
+                            fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
+                            if (fs->key->range && !p->type->isMutable())
+                            {
+                                /* Limit the range of the key to the specified range
+                                */
+                                v->range = new IntRange(fs->key->range->imin, fs->key->range->imax - SignExtendedNumber(1));
+                            }
+                        }
+                    }
+                    fs->_body = new CompoundStatement(loc, ds, fs->_body);
+
+                    s = new ForStatement(loc, forinit, cond, increment, fs->_body, fs->endloc);
+                    if (LabelStatement *ls = checkLabeledLoop(sc, fs))
+                        ls->gotoTarget = s;
+                    s = semantic(s, sc);
+                    break;
+                }
+
+            case Taarray:
+                if (fs->op == TOKforeach_reverse)
+                    fs->warning("cannot use foreach_reverse with an associative array");
+                if (fs->checkForArgTypes())
+                {
+                    result = fs;
+                    return;
+                }
+
+                taa = (TypeAArray *)tab;
+                if (dim < 1 || dim > 2)
+                {
+                    fs->error("only one or two arguments for associative array foreach");
+                    goto Lerror2;
+                }
+                goto Lapply;
+
+            case Tclass:
+            case Tstruct:
+                /* Prefer using opApply, if it exists
+                */
+                if (sapply)
+                    goto Lapply;
+
+                {
+                    /* Look for range iteration, i.e. the properties
+                     * .empty, .popFront, .popBack, .front and .back
+                     *    foreach (e; aggr) { ... }
+                     * translates to:
+                     *    for (auto __r = aggr[]; !__r.empty; __r.popFront()) {
+                     *        auto e = __r.front;
+                     *        ...
+                     *    }
+                     */
+                    AggregateDeclaration *ad = (tab->ty == Tclass)
+                        ? (AggregateDeclaration *)((TypeClass  *)tab)->sym
+                        : (AggregateDeclaration *)((TypeStruct *)tab)->sym;
+                    Identifier *idfront;
+                    Identifier *idpopFront;
+                    if (fs->op == TOKforeach)
+                    {
+                        idfront = Id::Ffront;
+                        idpopFront = Id::FpopFront;
+                    }
+                    else
+                    {
+                        idfront = Id::Fback;
+                        idpopFront = Id::FpopBack;
+                    }
+                    Dsymbol *sfront = ad->search(Loc(), idfront);
+                    if (!sfront)
+                        goto Lapply;
+
+                    /* Generate a temporary __r and initialize it with the aggregate.
+                     */
+                    VarDeclaration *r;
+                    Statement *init;
+                    if (vinit && fs->aggr->op == TOKvar && ((VarExp *)fs->aggr)->var == vinit)
+                    {
+                        r = vinit;
+                        init = new ExpStatement(loc, vinit);
+                    }
+                    else
+                    {
+                        r = copyToTemp(0, "__r", fs->aggr);
+                        init = new ExpStatement(loc, r);
+                        if (vinit)
+                            init = new CompoundStatement(loc, new ExpStatement(loc, vinit), init);
+                    }
+
+                    // !__r.empty
+                    Expression *e = new VarExp(loc, r);
+                    e = new DotIdExp(loc, e, Id::Fempty);
+                    Expression *condition = new NotExp(loc, e);
+
+                    // __r.idpopFront()
+                    e = new VarExp(loc, r);
+                    Expression *increment = new CallExp(loc, new DotIdExp(loc, e, idpopFront));
+
+                    /* Declaration statement for e:
+                     *    auto e = __r.idfront;
+                     */
+                    e = new VarExp(loc, r);
+                    Expression *einit = new DotIdExp(loc, e, idfront);
+                    Statement *makeargs, *forbody;
+                    if (dim == 1)
+                    {
+                        Parameter *p = (*fs->parameters)[0];
+                        VarDeclaration *ve = new VarDeclaration(loc, p->type, p->ident, new ExpInitializer(loc, einit));
+                        ve->storage_class |= STCforeach;
+                        ve->storage_class |= p->storageClass & (STCin | STCout | STCref | STC_TYPECTOR);
+
+                        makeargs = new ExpStatement(loc, ve);
+                    }
+                    else
+                    {
+                        VarDeclaration *vd = copyToTemp(STCref, "__front", einit);
+                        makeargs = new ExpStatement(loc, vd);
+
+                        Declaration *d = sfront->isDeclaration();
+                        if (FuncDeclaration *f = d->isFuncDeclaration())
+                        {
+                            if (!f->functionSemantic())
+                                goto Lrangeerr;
+                        }
+                        Expression *ve = new VarExp(loc, vd);
+                        ve->type = d->type;
+                        if (ve->type->toBasetype()->ty == Tfunction)
+                            ve->type = ve->type->toBasetype()->nextOf();
+                        if (!ve->type || ve->type->ty == Terror)
+                            goto Lrangeerr;
+
+                        // Resolve inout qualifier of front type
+                        ve->type = ve->type->substWildTo(tab->mod);
+
+                        Expressions *exps = new Expressions();
+                        exps->push(ve);
+                        int pos = 0;
+                        while (exps->dim < dim)
+                        {
+                            pos = expandAliasThisTuples(exps, pos);
+                            if (pos == -1)
+                                break;
+                        }
+                        if (exps->dim != dim)
+                        {
+                            const char *plural = exps->dim > 1 ? "s" : "";
+                            fs->error("cannot infer argument types, expected %d argument%s, not %d",
+                                      exps->dim, plural, dim);
+                            goto Lerror2;
+                        }
+
+                        for (size_t i = 0; i < dim; i++)
+                        {
+                            Parameter *p = (*fs->parameters)[i];
+                            Expression *exp = (*exps)[i];
+#if 0
+                            printf("[%d] p = %s %s, exp = %s %s\n", i,
+                                   p->type ? p->type->toChars() : "?", p->ident->toChars(),
+                                   exp->type->toChars(), exp->toChars());
+#endif
+                            if (!p->type)
+                                p->type = exp->type;
+                            p->type = p->type->addStorageClass(p->storageClass)->semantic(loc, sc);
+                            if (!exp->implicitConvTo(p->type))
+                                goto Lrangeerr;
+
+                            VarDeclaration *var = new VarDeclaration(loc, p->type, p->ident, new ExpInitializer(loc, exp));
+                            var->storage_class |= STCctfe | STCref | STCforeach;
+                            makeargs = new CompoundStatement(loc, makeargs, new ExpStatement(loc, var));
+                        }
+
+                    }
+
+                    forbody = new CompoundStatement(loc,
+                                                    makeargs, fs->_body);
+
+                    s = new ForStatement(loc, init, condition, increment, forbody, fs->endloc);
+                    if (LabelStatement *ls = checkLabeledLoop(sc, fs))
+                        ls->gotoTarget = s;
+#if 0
+                    printf("init: %s\n", init->toChars());
+                    printf("condition: %s\n", condition->toChars());
+                    printf("increment: %s\n", increment->toChars());
+                    printf("body: %s\n", forbody->toChars());
+#endif
+                    s = semantic(s, sc);
+                    break;
+
+                Lrangeerr:
+                    fs->error("cannot infer argument types");
+                    goto Lerror2;
+                }
+            case Tdelegate:
+                if (fs->op == TOKforeach_reverse)
+                    fs->deprecation("cannot use foreach_reverse with a delegate");
+            Lapply:
+                {
+                    if (fs->checkForArgTypes())
+                    {
+                        fs->_body = semanticNoScope(fs->_body, sc);
+                        result = fs;
+                        return;
+                    }
+
+                    TypeFunction *tfld = NULL;
+                    if (sapply)
+                    {
+                        FuncDeclaration *fdapply = sapply->isFuncDeclaration();
+                        if (fdapply)
+                        {
+                            assert(fdapply->type && fdapply->type->ty == Tfunction);
+                            tfld = (TypeFunction *)fdapply->type->semantic(loc, sc);
+                            goto Lget;
+                        }
+                        else if (tab->ty == Tdelegate)
+                        {
+                            tfld = (TypeFunction *)tab->nextOf();
+                        Lget:
+                            //printf("tfld = %s\n", tfld->toChars());
+                            if (tfld->parameters->dim == 1)
+                            {
+                                Parameter *p = Parameter::getNth(tfld->parameters, 0);
+                                if (p->type && p->type->ty == Tdelegate)
+                                {
+                                    Type *t = p->type->semantic(loc, sc);
+                                    assert(t->ty == Tdelegate);
+                                    tfld = (TypeFunction *)t->nextOf();
+                                }
+                            }
+                        }
+                    }
+
+                    /* Turn body into the function literal:
+                     *  int delegate(ref T param) { body }
+                     */
+                    Parameters *params = new Parameters();
+                    for (size_t i = 0; i < dim; i++)
+                    {
+                        Parameter *p = (*fs->parameters)[i];
+                        StorageClass stc = STCref;
+                        Identifier *id;
+
+                        p->type = p->type->semantic(loc, sc);
+                        p->type = p->type->addStorageClass(p->storageClass);
+                        if (tfld)
+                        {
+                            Parameter *prm = Parameter::getNth(tfld->parameters, i);
+                            //printf("\tprm = %s%s\n", (prm->storageClass&STCref?"ref ":""), prm->ident->toChars());
+                            stc = prm->storageClass & STCref;
+                            id = p->ident;    // argument copy is not need.
+                            if ((p->storageClass & STCref) != stc)
+                            {
+                                if (!stc)
+                                {
+                                    fs->error("foreach: cannot make %s ref", p->ident->toChars());
+                                    goto Lerror2;
+                                }
+                                goto LcopyArg;
+                            }
+                        }
+                        else if (p->storageClass & STCref)
+                        {
+                            // default delegate parameters are marked as ref, then
+                            // argument copy is not need.
+                            id = p->ident;
+                        }
+                        else
+                        {
+                            // Make a copy of the ref argument so it isn't
+                            // a reference.
+                        LcopyArg:
+                            id = Identifier::generateId("__applyArg", (int)i);
+
+                            Initializer *ie = new ExpInitializer(Loc(), new IdentifierExp(Loc(), id));
+                            VarDeclaration *v = new VarDeclaration(Loc(), p->type, p->ident, ie);
+                            v->storage_class |= STCtemp;
+                            s = new ExpStatement(Loc(), v);
+                            fs->_body = new CompoundStatement(loc, s, fs->_body);
+                        }
+                        params->push(new Parameter(stc, p->type, id, NULL));
+                    }
+                    // Bugzilla 13840: Throwable nested function inside nothrow function is acceptable.
+                    StorageClass stc = mergeFuncAttrs(STCsafe | STCpure | STCnogc, fs->func);
+                    tfld = new TypeFunction(params, Type::tint32, 0, LINKd, stc);
+                    fs->cases = new Statements();
+                    fs->gotos = new ScopeStatements();
+                    FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, Loc(), tfld, TOKdelegate, fs);
+                    fld->fbody = fs->_body;
+                    Expression *flde = new FuncExp(loc, fld);
+                    flde = semantic(flde, sc);
+                    fld->tookAddressOf = 0;
+
+                    // Resolve any forward referenced goto's
+                    for (size_t i = 0; i < fs->gotos->dim; i++)
+                    {
+                        GotoStatement *gs = (GotoStatement *)(*fs->gotos)[i]->statement;
+                        if (!gs->label->statement)
+                        {
+                            // 'Promote' it to this scope, and replace with a return
+                            fs->cases->push(gs);
+                            s = new ReturnStatement(Loc(), new IntegerExp(fs->cases->dim + 1));
+                            (*fs->gotos)[i]->statement = s;
+                        }
+                    }
+
+                    Expression *e = NULL;
+                    Expression *ec;
+                    if (vinit)
+                    {
+                        e = new DeclarationExp(loc, vinit);
+                        e = semantic(e, sc);
+                        if (e->op == TOKerror)
+                            goto Lerror2;
+                    }
+
+                    if (taa)
+                    {
+                        // Check types
+                        Parameter *p = (*fs->parameters)[0];
+                        bool isRef = (p->storageClass & STCref) != 0;
+                        Type *ta = p->type;
+                        if (dim == 2)
+                        {
+                            Type *ti = (isRef ? taa->index->addMod(MODconst) : taa->index);
+                            if (isRef ? !ti->constConv(ta) : !ti->implicitConvTo(ta))
+                            {
+                                fs->error("foreach: index must be type %s, not %s", ti->toChars(), ta->toChars());
+                                goto Lerror2;
+                            }
+                            p = (*fs->parameters)[1];
+                            isRef = (p->storageClass & STCref) != 0;
+                            ta = p->type;
+                        }
+                        Type *taav = taa->nextOf();
+                        if (isRef ? !taav->constConv(ta) : !taav->implicitConvTo(ta))
+                        {
+                            fs->error("foreach: value must be type %s, not %s", taav->toChars(), ta->toChars());
+                            goto Lerror2;
+                        }
+
+                        /* Call:
+                         *  extern(C) int _aaApply(void*, in size_t, int delegate(void*))
+                         *      _aaApply(aggr, keysize, flde)
+                         *
+                         *  extern(C) int _aaApply2(void*, in size_t, int delegate(void*, void*))
+                         *      _aaApply2(aggr, keysize, flde)
+                         */
+                        static const char *name[2] = { "_aaApply", "_aaApply2" };
+                        static FuncDeclaration *fdapply[2] = { NULL, NULL };
+                        static TypeDelegate *fldeTy[2] = { NULL, NULL };
+
+                        unsigned char i = (dim == 2 ? 1 : 0);
+                        if (!fdapply[i])
+                        {
+                            params = new Parameters();
+                            params->push(new Parameter(0, Type::tvoid->pointerTo(), NULL, NULL));
+                            params->push(new Parameter(STCin, Type::tsize_t, NULL, NULL));
+                            Parameters* dgparams = new Parameters;
+                            dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
+                            if (dim == 2)
+                                dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
+                            fldeTy[i] = new TypeDelegate(new TypeFunction(dgparams, Type::tint32, 0, LINKd));
+                            params->push(new Parameter(0, fldeTy[i], NULL, NULL));
+                            fdapply[i] = FuncDeclaration::genCfunc(params, Type::tint32, name[i]);
+                        }
+
+                        Expressions *exps = new Expressions();
+                        exps->push(fs->aggr);
+                        d_uns64 keysize = taa->index->size();
+                        if (keysize == SIZE_INVALID)
+                            goto Lerror2;
+                        assert(keysize < UINT64_MAX - Target::ptrsize);
+                        keysize = (keysize + (Target::ptrsize- 1)) & ~(Target::ptrsize - 1);
+                        // paint delegate argument to the type runtime expects
+                        if (!fldeTy[i]->equals(flde->type))
+                        {
+                            flde = new CastExp(loc, flde, flde->type);
+                            flde->type = fldeTy[i];
+                        }
+                        exps->push(new IntegerExp(Loc(), keysize, Type::tsize_t));
+                        exps->push(flde);
+
+                        ec = new VarExp(Loc(), fdapply[i], false);
+                        ec = new CallExp(loc, ec, exps);
+                        ec->type = Type::tint32; // don't run semantic() on ec
+                    }
+                    else if (tab->ty == Tarray || tab->ty == Tsarray)
+                    {
+                        /* Call:
+                         *      _aApply(aggr, flde)
+                         */
+                        static const char fntab[9][3] =
+                        { "cc","cw","cd",
+                            "wc","cc","wd",
+                            "dc","dw","dd"
+                        };
+                        const size_t BUFFER_LEN = 7+1+2+ sizeof(dim)*3 + 1;
+                        char fdname[BUFFER_LEN];
+                        int flag;
+
+                        switch (tn->ty)
+                        {
+                            case Tchar:         flag = 0; break;
+                            case Twchar:        flag = 3; break;
+                            case Tdchar:        flag = 6; break;
+                            default:            assert(0);
+                        }
+                        switch (tnv->ty)
+                        {
+                            case Tchar:         flag += 0; break;
+                            case Twchar:        flag += 1; break;
+                            case Tdchar:        flag += 2; break;
+                            default:            assert(0);
+                        }
+                        const char *r = (fs->op == TOKforeach_reverse) ? "R" : "";
+                        int j = sprintf(fdname, "_aApply%s%.*s%llu", r, 2, fntab[flag], (ulonglong)dim);
+                        assert(j < BUFFER_LEN);
+
+                        FuncDeclaration *fdapply;
+                        TypeDelegate *dgty;
+                        params = new Parameters();
+                        params->push(new Parameter(STCin, tn->arrayOf(), NULL, NULL));
+                        Parameters* dgparams = new Parameters;
+                        dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
+                        if (dim == 2)
+                            dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
+                        dgty = new TypeDelegate(new TypeFunction(dgparams, Type::tint32, 0, LINKd));
+                        params->push(new Parameter(0, dgty, NULL, NULL));
+                        fdapply = FuncDeclaration::genCfunc(params, Type::tint32, fdname);
+
+                        if (tab->ty == Tsarray)
+                            fs->aggr = fs->aggr->castTo(sc, tn->arrayOf());
+
+                        // paint delegate argument to the type runtime expects
+                        if (!dgty->equals(flde->type)) {
+                            flde = new CastExp(loc, flde, flde->type);
+                            flde->type = dgty;
+                        }
+
+                        ec = new VarExp(Loc(), fdapply, false);
+                        ec = new CallExp(loc, ec, fs->aggr, flde);
+                        ec->type = Type::tint32; // don't run semantic() on ec
+                    }
+                    else if (tab->ty == Tdelegate)
+                    {
+                        /* Call:
+                         *      aggr(flde)
+                         */
+                        if (fs->aggr->op == TOKdelegate &&
+                            ((DelegateExp *)fs->aggr)->func->isNested())
+                        {
+                            // See Bugzilla 3560
+                            fs->aggr = ((DelegateExp *)fs->aggr)->e1;
+                        }
+                        ec = new CallExp(loc, fs->aggr, flde);
+                        ec = semantic(ec, sc);
+                        if (ec->op == TOKerror)
+                            goto Lerror2;
+                        if (ec->type != Type::tint32)
+                        {
+                            fs->error("opApply() function for %s must return an int", tab->toChars());
+                            goto Lerror2;
+                        }
+                    }
+                    else
+                    {
+                        if (global.params.vsafe)
+                            fld->tookAddressOf = 1;  // allocate a closure unless the opApply() uses 'scope'
+
+                        assert(tab->ty == Tstruct || tab->ty == Tclass);
+                        assert(sapply);
+                        /* Call:
+                         *  aggr.apply(flde)
+                         */
+                        ec = new DotIdExp(loc, fs->aggr, sapply->ident);
+                        ec = new CallExp(loc, ec, flde);
+                        ec = semantic(ec, sc);
+                        if (ec->op == TOKerror)
+                            goto Lerror2;
+                        if (ec->type != Type::tint32)
+                        {
+                            fs->error("opApply() function for %s must return an int", tab->toChars());
+                            goto Lerror2;
+                        }
+                    }
+                    e = Expression::combine(e, ec);
+
+                    if (!fs->cases->dim)
+                    {
+                        // Easy case, a clean exit from the loop
+                        e = new CastExp(loc, e, Type::tvoid);   // Bugzilla 13899
+                        s = new ExpStatement(loc, e);
+                    }
+                    else
+                    {
+                        // Construct a switch statement around the return value
+                        // of the apply function.
+                        Statements *a = new Statements();
+
+                        // default: break; takes care of cases 0 and 1
+                        s = new BreakStatement(Loc(), NULL);
+                        s = new DefaultStatement(Loc(), s);
+                        a->push(s);
+
+                        // cases 2...
+                        for (size_t i = 0; i < fs->cases->dim; i++)
+                        {
+                            s = (*fs->cases)[i];
+                            s = new CaseStatement(Loc(), new IntegerExp(i + 2), s);
+                            a->push(s);
+                        }
+
+                        s = new CompoundStatement(loc, a);
+                        s = new SwitchStatement(loc, e, s, false);
+                    }
+                    s = semantic(s, sc);
+                    break;
+                }
+            case Terror:
+            Lerror2:
+                s = new ErrorStatement();
+                break;
+
+            default:
+                fs->error("foreach: %s is not an aggregate type", fs->aggr->type->toChars());
+                goto Lerror2;
+        }
+        sc->noctor--;
+        sc->pop();
+        result = s;
+    }
+
+    void visit(ForeachRangeStatement *fs)
+    {
+        //printf("ForeachRangeStatement::semantic() %p\n", fs);
+        Loc loc = fs->loc;
+        fs->lwr = semantic(fs->lwr, sc);
+        fs->lwr = resolveProperties(sc, fs->lwr);
+        fs->lwr = fs->lwr->optimize(WANTvalue);
+        if (!fs->lwr->type)
+        {
+            fs->error("invalid range lower bound %s", fs->lwr->toChars());
+        Lerror:
+            return setError();
+        }
+
+        fs->upr = semantic(fs->upr, sc);
+        fs->upr = resolveProperties(sc, fs->upr);
+        fs->upr = fs->upr->optimize(WANTvalue);
+        if (!fs->upr->type)
+        {
+            fs->error("invalid range upper bound %s", fs->upr->toChars());
+            goto Lerror;
+        }
+
+        if (fs->prm->type)
+        {
+            fs->prm->type = fs->prm->type->semantic(loc, sc);
+            fs->prm->type = fs->prm->type->addStorageClass(fs->prm->storageClass);
+            fs->lwr = fs->lwr->implicitCastTo(sc, fs->prm->type);
+
+            if (fs->upr->implicitConvTo(fs->prm->type) || (fs->prm->storageClass & STCref))
+            {
+                fs->upr = fs->upr->implicitCastTo(sc, fs->prm->type);
+            }
+            else
+            {
+                // See if upr-1 fits in prm->type
+                Expression *limit = new MinExp(loc, fs->upr, new IntegerExp(1));
+                limit = semantic(limit, sc);
+                limit = limit->optimize(WANTvalue);
+                if (!limit->implicitConvTo(fs->prm->type))
+                {
+                    fs->upr = fs->upr->implicitCastTo(sc, fs->prm->type);
+                }
+            }
+        }
+        else
+        {
+            /* Must infer types from lwr and upr
+            */
+            Type *tlwr = fs->lwr->type->toBasetype();
+            if (tlwr->ty == Tstruct || tlwr->ty == Tclass)
+            {
+                /* Just picking the first really isn't good enough.
+                */
+                fs->prm->type = fs->lwr->type;
+            }
+            else if (fs->lwr->type == fs->upr->type)
+            {
+                /* Same logic as CondExp ?lwr:upr
+                */
+                fs->prm->type = fs->lwr->type;
+            }
+            else
+            {
+                AddExp ea(loc, fs->lwr, fs->upr);
+                if (typeCombine(&ea, sc))
+                    return setError();
+                fs->prm->type = ea.type;
+                fs->lwr = ea.e1;
+                fs->upr = ea.e2;
+            }
+            fs->prm->type = fs->prm->type->addStorageClass(fs->prm->storageClass);
+        }
+        if (fs->prm->type->ty == Terror ||
+            fs->lwr->op == TOKerror ||
+            fs->upr->op == TOKerror)
+        {
+            return setError();
+        }
+
+        /* Convert to a for loop:
+         *  foreach (key; lwr .. upr) =>
+         *  for (auto key = lwr, auto tmp = upr; key < tmp; ++key)
+         *
+         *  foreach_reverse (key; lwr .. upr) =>
+         *  for (auto tmp = lwr, auto key = upr; key-- > tmp;)
+         */
+        ExpInitializer *ie = new ExpInitializer(loc, (fs->op == TOKforeach) ? fs->lwr : fs->upr);
+        fs->key = new VarDeclaration(loc, fs->upr->type->mutableOf(), Identifier::generateId("__key"), ie);
+        fs->key->storage_class |= STCtemp;
+        SignExtendedNumber lower = getIntRange(fs->lwr).imin;
+        SignExtendedNumber upper = getIntRange(fs->upr).imax;
+        if (lower <= upper)
+        {
+            fs->key->range = new IntRange(lower, upper);
+        }
+
+        Identifier *id = Identifier::generateId("__limit");
+        ie = new ExpInitializer(loc, (fs->op == TOKforeach) ? fs->upr : fs->lwr);
+        VarDeclaration *tmp = new VarDeclaration(loc, fs->upr->type, id, ie);
+        tmp->storage_class |= STCtemp;
+
+        Statements *cs = new Statements();
+        // Keep order of evaluation as lwr, then upr
+        if (fs->op == TOKforeach)
+        {
+            cs->push(new ExpStatement(loc, fs->key));
+            cs->push(new ExpStatement(loc, tmp));
+        }
+        else
+        {
+            cs->push(new ExpStatement(loc, tmp));
+            cs->push(new ExpStatement(loc, fs->key));
+        }
+        Statement *forinit = new CompoundDeclarationStatement(loc, cs);
+
+        Expression *cond;
+        if (fs->op == TOKforeach_reverse)
+        {
+            cond = new PostExp(TOKminusminus, loc, new VarExp(loc, fs->key));
+            if (fs->prm->type->isscalar())
+            {
+                // key-- > tmp
+                cond = new CmpExp(TOKgt, loc, cond, new VarExp(loc, tmp));
+            }
+            else
+            {
+                // key-- != tmp
+                cond = new EqualExp(TOKnotequal, loc, cond, new VarExp(loc, tmp));
+            }
+        }
+        else
+        {
+            if (fs->prm->type->isscalar())
+            {
+                // key < tmp
+                cond = new CmpExp(TOKlt, loc, new VarExp(loc, fs->key), new VarExp(loc, tmp));
+            }
+            else
+            {
+                // key != tmp
+                cond = new EqualExp(TOKnotequal, loc, new VarExp(loc, fs->key), new VarExp(loc, tmp));
+            }
+        }
+
+        Expression *increment = NULL;
+        if (fs->op == TOKforeach)
+        {
+            // key += 1
+            //increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1));
+            increment = new PreExp(TOKpreplusplus, loc, new VarExp(loc, fs->key));
+        }
+
+        if ((fs->prm->storageClass & STCref) && fs->prm->type->equals(fs->key->type))
+        {
+            fs->key->range = NULL;
+            AliasDeclaration *v = new AliasDeclaration(loc, fs->prm->ident, fs->key);
+            fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
+        }
+        else
+        {
+            ie = new ExpInitializer(loc, new CastExp(loc, new VarExp(loc, fs->key), fs->prm->type));
+            VarDeclaration *v = new VarDeclaration(loc, fs->prm->type, fs->prm->ident, ie);
+            v->storage_class |= STCtemp | STCforeach | (fs->prm->storageClass & STCref);
+            fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
+            if (fs->key->range && !fs->prm->type->isMutable())
+            {
+                /* Limit the range of the key to the specified range
+                */
+                v->range = new IntRange(fs->key->range->imin, fs->key->range->imax - SignExtendedNumber(1));
+            }
+        }
+        if (fs->prm->storageClass & STCref)
+        {
+            if (fs->key->type->constConv(fs->prm->type) <= MATCHnomatch)
+            {
+                fs->error("prmument type mismatch, %s to ref %s",
+                          fs->key->type->toChars(), fs->prm->type->toChars());
+                goto Lerror;
+            }
+        }
+
+        ForStatement *s = new ForStatement(loc, forinit, cond, increment, fs->_body, fs->endloc);
+        if (LabelStatement *ls = checkLabeledLoop(sc, fs))
+            ls->gotoTarget = s;
+        result = semantic(s, sc);
+    }
+
+    void visit(IfStatement *ifs)
+    {
+        // Evaluate at runtime
+        unsigned cs0 = sc->callSuper;
+        unsigned cs1;
+        unsigned *fi0 = sc->saveFieldInit();
+        unsigned *fi1 = NULL;
+
+        // check in syntax level
+        ifs->condition = checkAssignmentAsCondition(ifs->condition);
+
+        ScopeDsymbol *sym = new ScopeDsymbol();
+        sym->parent = sc->scopesym;
+        sym->endlinnum = ifs->endloc.linnum;
+        Scope *scd = sc->push(sym);
+        if (ifs->prm)
+        {
+            /* Declare prm, which we will set to be the
+             * result of condition.
+             */
+            ExpInitializer *ei = new ExpInitializer(ifs->loc, ifs->condition);
+            ifs->match = new VarDeclaration(ifs->loc, ifs->prm->type, ifs->prm->ident, ei);
+            ifs->match->parent = sc->func;
+            ifs->match->storage_class |= ifs->prm->storageClass;
+
+            DeclarationExp *de = new DeclarationExp(ifs->loc, ifs->match);
+            VarExp *ve = new VarExp(Loc(), ifs->match);
+            ifs->condition = new CommaExp(ifs->loc, de, ve);
+            ifs->condition = semantic(ifs->condition, scd);
+
+            if (ifs->match->edtor)
+            {
+                Statement *sdtor = new DtorExpStatement(ifs->loc, ifs->match->edtor, ifs->match);
+                sdtor = new OnScopeStatement(ifs->loc, TOKon_scope_exit, sdtor);
+                ifs->ifbody = new CompoundStatement(ifs->loc, sdtor, ifs->ifbody);
+                ifs->match->storage_class |= STCnodtor;
+            }
+        }
+        else
+        {
+            if (ifs->condition->op == TOKdotid)
+                ((DotIdExp *)ifs->condition)->noderef = true;
+
+            ifs->condition = semantic(ifs->condition, sc);
+            ifs->condition = resolveProperties(sc, ifs->condition);
+            ifs->condition = ifs->condition->addDtorHook(sc);
+        }
+        ifs->condition = checkGC(sc, ifs->condition);
+
+        // Convert to boolean after declaring prm so this works:
+        //  if (S prm = S()) {}
+        // where S is a struct that defines opCast!bool.
+        ifs->condition = ifs->condition->toBoolean(sc);
+
+        // If we can short-circuit evaluate the if statement, don't do the
+        // semantic analysis of the skipped code.
+        // This feature allows a limited form of conditional compilation.
+        ifs->condition = ifs->condition->optimize(WANTvalue);
+        ifs->ifbody = semanticNoScope(ifs->ifbody, scd);
+        scd->pop();
+
+        cs1 = sc->callSuper;
+        fi1 = sc->fieldinit;
+        sc->callSuper = cs0;
+        sc->fieldinit = fi0;
+        if (ifs->elsebody)
+            ifs->elsebody = semanticScope(ifs->elsebody, sc, NULL, NULL);
+        sc->mergeCallSuper(ifs->loc, cs1);
+        sc->mergeFieldInit(ifs->loc, fi1);
+
+        if (ifs->condition->op == TOKerror ||
+            (ifs->ifbody && ifs->ifbody->isErrorStatement()) ||
+            (ifs->elsebody && ifs->elsebody->isErrorStatement()))
+        {
+            return setError();
+        }
+        result = ifs;
+    }
+
+    void visit(ConditionalStatement *cs)
+    {
+        //printf("ConditionalStatement::semantic()\n");
+
+        // If we can short-circuit evaluate the if statement, don't do the
+        // semantic analysis of the skipped code.
+        // This feature allows a limited form of conditional compilation.
+        if (cs->condition->include(sc, NULL))
+        {
+            DebugCondition *dc = cs->condition->isDebugCondition();
+            if (dc)
+            {
+                sc = sc->push();
+                sc->flags |= SCOPEdebug;
+                cs->ifbody = semantic(cs->ifbody, sc);
+                sc->pop();
+            }
+            else
+                cs->ifbody = semantic(cs->ifbody, sc);
+            result = cs->ifbody;
+        }
+        else
+        {
+            if (cs->elsebody)
+                cs->elsebody = semantic(cs->elsebody, sc);
+            result = cs->elsebody;
+        }
+    }
+
+    void visit(PragmaStatement *ps)
+    {
+        // Should be merged with PragmaDeclaration
+        //printf("PragmaStatement::semantic() %s\n", ps->toChars());
+        //printf("body = %p\n", ps->_body);
+        if (ps->ident == Id::msg)
+        {
+            if (ps->args)
+            {
+                for (size_t i = 0; i < ps->args->dim; i++)
+                {
+                    Expression *e = (*ps->args)[i];
+
+                    sc = sc->startCTFE();
+                    e = semantic(e, sc);
+                    e = resolveProperties(sc, e);
+                    sc = sc->endCTFE();
+                    // pragma(msg) is allowed to contain types as well as expressions
+                    e = ctfeInterpretForPragmaMsg(e);
+                    if (e->op == TOKerror)
+                    {
+                        errorSupplemental(ps->loc, "while evaluating pragma(msg, %s)", (*ps->args)[i]->toChars());
+                        goto Lerror;
+                    }
+                    StringExp *se = e->toStringExp();
+                    if (se)
+                    {
+                        se = se->toUTF8(sc);
+                        fprintf(stderr, "%.*s", (int)se->len, (char *)se->string);
+                    }
+                    else
+                        fprintf(stderr, "%s", e->toChars());
+                }
+                fprintf(stderr, "\n");
+            }
+        }
+        else if (ps->ident == Id::lib)
+        {
+#if 1
+            /* Should this be allowed?
+            */
+            ps->error("pragma(lib) not allowed as statement");
+            goto Lerror;
+#else
+            if (!ps->args || ps->args->dim != 1)
+            {
+                ps->error("string expected for library name");
+                goto Lerror;
+            }
+            else
+            {
+                Expression *e = (*ps->args)[0];
+
+                sc = sc->startCTFE();
+                e = semantic(e, sc);
+                e = resolveProperties(sc, e);
+                sc = sc->endCTFE();
+
+                e = e->ctfeInterpret();
+                (*ps->args)[0] = e;
+                StringExp *se = e->toStringExp();
+                if (!se)
+                {
+                    ps->error("string expected for library name, not '%s'", e->toChars());
+                    goto Lerror;
+                }
+                else if (global.params.verbose)
+                {
+                    char *name = (char *)mem.malloc(se->len + 1);
+                    memcpy(name, se->string, se->len);
+                    name[se->len] = 0;
+                    fprintf(global.stdmsg, "library   %s\n", name);
+                    mem.free(name);
+                }
+            }
+#endif
+        }
+        else if (ps->ident == Id::startaddress)
+        {
+            if (!ps->args || ps->args->dim != 1)
+                ps->error("function name expected for start address");
+            else
+            {
+                Expression *e = (*ps->args)[0];
+
+                sc = sc->startCTFE();
+                e = semantic(e, sc);
+                e = resolveProperties(sc, e);
+                sc = sc->endCTFE();
+
+                e = e->ctfeInterpret();
+                (*ps->args)[0] = e;
+                Dsymbol *sa = getDsymbol(e);
+                if (!sa || !sa->isFuncDeclaration())
+                {
+                    ps->error("function name expected for start address, not '%s'", e->toChars());
+                    goto Lerror;
+                }
+                if (ps->_body)
+                {
+                    ps->_body = semantic(ps->_body, sc);
+                    if (ps->_body->isErrorStatement())
+                    {
+                        result = ps->_body;
+                        return;
+                    }
+                }
+                result = ps;
+                return;
+            }
+        }
+        else if (ps->ident == Id::Pinline)
+        {
+            PINLINE inlining = PINLINEdefault;
+            if (!ps->args || ps->args->dim == 0)
+                inlining = PINLINEdefault;
+            else if (!ps->args || ps->args->dim != 1)
+            {
+                ps->error("boolean expression expected for pragma(inline)");
+                goto Lerror;
+            }
+            else
+            {
+                Expression *e = (*ps->args)[0];
+
+                if (e->op != TOKint64 || !e->type->equals(Type::tbool))
+                {
+                    ps->error("pragma(inline, true or false) expected, not %s", e->toChars());
+                    goto Lerror;
+                }
+
+                if (e->isBool(true))
+                    inlining = PINLINEalways;
+                else if (e->isBool(false))
+                    inlining = PINLINEnever;
+
+                FuncDeclaration *fd = sc->func;
+                if (!fd)
+                {
+                    ps->error("pragma(inline) is not inside a function");
+                    goto Lerror;
+                }
+                fd->inlining = inlining;
+            }
+        }
+        else
+        {
+            ps->error("unrecognized pragma(%s)", ps->ident->toChars());
+            goto Lerror;
+        }
+
+        if (ps->_body)
+        {
+            ps->_body = semantic(ps->_body, sc);
+        }
+        result = ps->_body;
+        return;
+
+    Lerror:
+        return setError();
+    }
+
+    void visit(StaticAssertStatement *s)
+    {
+        s->sa->semantic2(sc);
+    }
+
+    void visit(SwitchStatement *ss)
+    {
+        //printf("SwitchStatement::semantic(%p)\n", ss);
+        ss->tf = sc->tf;
+        if (ss->cases)
+        {
+            result = ss;            // already run
+            return;
+        }
+        bool conditionError = false;
+        ss->condition = semantic(ss->condition, sc);
+        ss->condition = resolveProperties(sc, ss->condition);
+        TypeEnum *te = NULL;
+        // preserve enum type for final switches
+        if (ss->condition->type->ty == Tenum)
+            te = (TypeEnum *)ss->condition->type;
+        if (ss->condition->type->isString())
+        {
+            // If it's not an array, cast it to one
+            if (ss->condition->type->ty != Tarray)
+            {
+                ss->condition = ss->condition->implicitCastTo(sc, ss->condition->type->nextOf()->arrayOf());
+            }
+            ss->condition->type = ss->condition->type->constOf();
+        }
+        else
+        {
+            ss->condition = integralPromotions(ss->condition, sc);
+            if (ss->condition->op != TOKerror && !ss->condition->type->isintegral())
+            {
+                ss->error("'%s' must be of integral or string type, it is a %s", ss->condition->toChars(), ss->condition->type->toChars());
+                conditionError = true;
+            }
+        }
+        ss->condition = ss->condition->optimize(WANTvalue);
+        ss->condition = checkGC(sc, ss->condition);
+        if (ss->condition->op == TOKerror)
+            conditionError = true;
+
+        bool needswitcherror = false;
+
+        ss->lastVar = sc->lastVar;
+
+        sc = sc->push();
+        sc->sbreak = ss;
+        sc->sw = ss;
+
+        ss->cases = new CaseStatements();
+        sc->noctor++;       // BUG: should use Scope::mergeCallSuper() for each case instead
+        ss->_body = semantic(ss->_body, sc);
+        sc->noctor--;
+
+        if (conditionError || ss->_body->isErrorStatement())
+            goto Lerror;
+
+        // Resolve any goto case's with exp
+        for (size_t i = 0; i < ss->gotoCases.dim; i++)
+        {
+            GotoCaseStatement *gcs = ss->gotoCases[i];
+
+            if (!gcs->exp)
+            {
+                gcs->error("no case statement following goto case;");
+                goto Lerror;
+            }
+
+            for (Scope *scx = sc; scx; scx = scx->enclosing)
+            {
+                if (!scx->sw)
+                    continue;
+                for (size_t j = 0; j < scx->sw->cases->dim; j++)
+                {
+                    CaseStatement *cs = (*scx->sw->cases)[j];
+
+                    if (cs->exp->equals(gcs->exp))
+                    {
+                        gcs->cs = cs;
+                        goto Lfoundcase;
+                    }
+                }
+            }
+            gcs->error("case %s not found", gcs->exp->toChars());
+            goto Lerror;
+
+        Lfoundcase:
+            ;
+        }
+
+        if (ss->isFinal)
+        {
+            Type *t = ss->condition->type;
+            Dsymbol *ds;
+            EnumDeclaration *ed = NULL;
+            if (t && ((ds = t->toDsymbol(sc)) != NULL))
+                ed = ds->isEnumDeclaration();  // typedef'ed enum
+            if (!ed && te && ((ds = te->toDsymbol(sc)) != NULL))
+                ed = ds->isEnumDeclaration();
+            if (ed)
+            {
+                size_t dim = ed->members->dim;
+                for (size_t i = 0; i < dim; i++)
+                {
+                    EnumMember *em = (*ed->members)[i]->isEnumMember();
+                    if (em)
+                    {
+                        for (size_t j = 0; j < ss->cases->dim; j++)
+                        {
+                            CaseStatement *cs = (*ss->cases)[j];
+                            if (cs->exp->equals(em->value()) ||
+                                (!cs->exp->type->isString() && !em->value()->type->isString() &&
+                                 cs->exp->toInteger() == em->value()->toInteger()))
+                                goto L1;
+                        }
+                        ss->error("enum member %s not represented in final switch", em->toChars());
+                        goto Lerror;
+                    }
+                L1:
+                    ;
+                }
+            }
+            else
+                needswitcherror = true;
+        }
+
+        if (!sc->sw->sdefault && (!ss->isFinal || needswitcherror || global.params.useAssert))
+        {
+            ss->hasNoDefault = 1;
+
+            if (!ss->isFinal && !ss->_body->isErrorStatement())
+                ss->error("switch statement without a default; use 'final switch' or add 'default: assert(0);' or add 'default: break;'");
+
+            // Generate runtime error if the default is hit
+            Statements *a = new Statements();
+            CompoundStatement *cs;
+            Statement *s;
+
+            if (global.params.useSwitchError)
+                s = new SwitchErrorStatement(ss->loc);
+            else
+                s = new ExpStatement(ss->loc, new HaltExp(ss->loc));
+
+            a->reserve(2);
+            sc->sw->sdefault = new DefaultStatement(ss->loc, s);
+            a->push(ss->_body);
+            if (blockExit(ss->_body, sc->func, false) & BEfallthru)
+                a->push(new BreakStatement(Loc(), NULL));
+            a->push(sc->sw->sdefault);
+            cs = new CompoundStatement(ss->loc, a);
+            ss->_body = cs;
+        }
+
+        if (ss->checkLabel())
+            goto Lerror;
+
+        sc->pop();
+        result = ss;
+        return;
+
+    Lerror:
+        sc->pop();
+        result = new ErrorStatement();
+    }
+
+    void visit(CaseStatement *cs)
+    {
+        SwitchStatement *sw = sc->sw;
+        bool errors = false;
+
+        //printf("CaseStatement::semantic() %s\n", cs->toChars());
+        sc = sc->startCTFE();
+        cs->exp = semantic(cs->exp, sc);
+        cs->exp = resolveProperties(sc, cs->exp);
+        sc = sc->endCTFE();
+        if (sw)
+        {
+            cs->exp = cs->exp->implicitCastTo(sc, sw->condition->type);
+            cs->exp = cs->exp->optimize(WANTvalue);
+
+            /* This is where variables are allowed as case expressions.
+            */
+            if (cs->exp->op == TOKvar)
+            {
+                VarExp *ve = (VarExp *)cs->exp;
+                VarDeclaration *v = ve->var->isVarDeclaration();
+                Type *t = cs->exp->type->toBasetype();
+                if (v && (t->isintegral() || t->ty == Tclass))
+                {
+                    /* Flag that we need to do special code generation
+                     * for this, i.e. generate a sequence of if-then-else
+                     */
+                    sw->hasVars = 1;
+
+                    /* TODO check if v can be uninitialized at that point.
+                     */
+                    if (!v->isConst() && !v->isImmutable())
+                    {
+                        cs->deprecation("case variables have to be const or immutable");
+                    }
+
+                    if (sw->isFinal)
+                    {
+                        cs->error("case variables not allowed in final switch statements");
+                        errors = true;
+                    }
+
+                    /* Also check if the VarExp is declared in a scope outside of this one.
+                     * 'scx' is set to the scope of the switch statement.
+                     */
+                    for (Scope *scx = sc; scx; scx = scx->enclosing)
+                    {
+                        if (scx->enclosing && scx->enclosing->sw == sw)
+                            continue;
+                        assert(scx->sw == sw);
+
+                        if (!scx->search(cs->exp->loc, v->ident, NULL))
+                        {
+                            cs->error("case variable `%s` declared at %s cannot be declared in switch body",
+                                v->toChars(), v->loc.toChars());
+                            errors = true;
+                        }
+                        break;
+                    }
+                    goto L1;
+                }
+            }
+            else
+                cs->exp = cs->exp->ctfeInterpret();
+
+            if (StringExp *se = cs->exp->toStringExp())
+                cs->exp = se;
+            else if (cs->exp->op != TOKint64 && cs->exp->op != TOKerror)
+            {
+                cs->error("case must be a string or an integral constant, not %s", cs->exp->toChars());
+                errors = true;
+            }
+
+        L1:
+            for (size_t i = 0; i < sw->cases->dim; i++)
+            {
+                CaseStatement *cs2 = (*sw->cases)[i];
+
+                //printf("comparing '%s' with '%s'\n", cs->exp->toChars(), cs2->exp->toChars());
+                if (cs2->exp->equals(cs->exp))
+                {
+                    cs->error("duplicate case %s in switch statement", cs->exp->toChars());
+                    errors = true;
+                    break;
+                }
+            }
+
+            sw->cases->push(cs);
+
+            // Resolve any goto case's with no exp to this case statement
+            for (size_t i = 0; i < sw->gotoCases.dim; )
+            {
+                GotoCaseStatement *gcs = sw->gotoCases[i];
+
+                if (!gcs->exp)
+                {
+                    gcs->cs = cs;
+                    sw->gotoCases.remove(i);        // remove from array
+                    continue;
+                }
+                i++;
+            }
+
+            if (sc->sw->tf != sc->tf)
+            {
+                cs->error("switch and case are in different finally blocks");
+                errors = true;
+            }
+        }
+        else
+        {
+            cs->error("case not in switch statement");
+            errors = true;
+        }
+        cs->statement = semantic(cs->statement, sc);
+        if (cs->statement->isErrorStatement())
+        {
+            result = cs->statement;
+            return;
+        }
+        if (errors || cs->exp->op == TOKerror)
+            return setError();
+
+        cs->lastVar = sc->lastVar;
+        result = cs;
+    }
+
+    void visit(CaseRangeStatement *crs)
+    {
+        SwitchStatement *sw = sc->sw;
+        if (sw == NULL)
+        {
+            crs->error("case range not in switch statement");
+            return setError();
+        }
+
+        //printf("CaseRangeStatement::semantic() %s\n", toChars());
+        bool errors = false;
+        if (sw->isFinal)
+        {
+            crs->error("case ranges not allowed in final switch");
+            errors = true;
+        }
+
+        sc = sc->startCTFE();
+        crs->first = semantic(crs->first, sc);
+        crs->first = resolveProperties(sc, crs->first);
+        sc = sc->endCTFE();
+        crs->first = crs->first->implicitCastTo(sc, sw->condition->type);
+        crs->first = crs->first->ctfeInterpret();
+
+        sc = sc->startCTFE();
+        crs->last = semantic(crs->last, sc);
+        crs->last = resolveProperties(sc, crs->last);
+        sc = sc->endCTFE();
+        crs->last = crs->last->implicitCastTo(sc, sw->condition->type);
+        crs->last = crs->last->ctfeInterpret();
+
+        if (crs->first->op == TOKerror || crs->last->op == TOKerror || errors)
+        {
+            if (crs->statement)
+                semantic(crs->statement, sc);
+            return setError();
+        }
+
+        uinteger_t fval = crs->first->toInteger();
+        uinteger_t lval = crs->last->toInteger();
+
+
+        if ( (crs->first->type->isunsigned()  &&  fval > lval) ||
+             (!crs->first->type->isunsigned()  &&  (sinteger_t)fval > (sinteger_t)lval))
+        {
+            crs->error("first case %s is greater than last case %s",
+                       crs->first->toChars(), crs->last->toChars());
+            errors = true;
+            lval = fval;
+        }
+
+        if (lval - fval > 256)
+        {
+            crs->error("had %llu cases which is more than 256 cases in case range", lval - fval);
+            errors = true;
+            lval = fval + 256;
+        }
+
+        if (errors)
+            return setError();
+
+        /* This works by replacing the CaseRange with an array of Case's.
+         *
+         * case a: .. case b: s;
+         *    =>
+         * case a:
+         *   [...]
+         * case b:
+         *   s;
+         */
+
+        Statements *statements = new Statements();
+        for (uinteger_t i = fval; i != lval + 1; i++)
+        {
+            Statement *s = crs->statement;
+            if (i != lval)                          // if not last case
+                s = new ExpStatement(crs->loc, (Expression *)NULL);
+            Expression *e = new IntegerExp(crs->loc, i, crs->first->type);
+            Statement *cs = new CaseStatement(crs->loc, e, s);
+            statements->push(cs);
+        }
+        Statement *s = new CompoundStatement(crs->loc, statements);
+        s = semantic(s, sc);
+        result = s;
+    }
+
+    void visit(DefaultStatement *ds)
+    {
+        //printf("DefaultStatement::semantic()\n");
+        bool errors = false;
+        if (sc->sw)
+        {
+            if (sc->sw->sdefault)
+            {
+                ds->error("switch statement already has a default");
+                errors = true;
+            }
+            sc->sw->sdefault = ds;
+
+            if (sc->sw->tf != sc->tf)
+            {
+                ds->error("switch and default are in different finally blocks");
+                errors = true;
+            }
+            if (sc->sw->isFinal)
+            {
+                ds->error("default statement not allowed in final switch statement");
+                errors = true;
+            }
+        }
+        else
+        {
+            ds->error("default not in switch statement");
+            errors = true;
+        }
+        ds->statement = semantic(ds->statement, sc);
+        if (errors || ds->statement->isErrorStatement())
+            return setError();
+
+        ds->lastVar = sc->lastVar;
+        result = ds;
+    }
+
+    void visit(GotoDefaultStatement *gds)
+    {
+        gds->sw = sc->sw;
+        if (!gds->sw)
+        {
+            gds->error("goto default not in switch statement");
+            return setError();
+        }
+        result = gds;
+    }
+
+    void visit(GotoCaseStatement *gcs)
+    {
+        if (!sc->sw)
+        {
+            gcs->error("goto case not in switch statement");
+            return setError();
+        }
+
+        if (gcs->exp)
+        {
+            gcs->exp = semantic(gcs->exp, sc);
+            gcs->exp = gcs->exp->implicitCastTo(sc, sc->sw->condition->type);
+            gcs->exp = gcs->exp->optimize(WANTvalue);
+            if (gcs->exp->op == TOKerror)
+                return setError();
+        }
+
+        sc->sw->gotoCases.push(gcs);
+        result = gcs;
+    }
+
+    void visit(ReturnStatement *rs)
+    {
+        //printf("ReturnStatement::semantic() %s\n", toChars());
+
+        FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+
+        if (fd->fes)
+            fd = fd->fes->func;             // fd is now function enclosing foreach
+
+        TypeFunction *tf = (TypeFunction *)fd->type;
+        assert(tf->ty == Tfunction);
+
+        if (rs->exp && rs->exp->op == TOKvar && ((VarExp *)rs->exp)->var == fd->vresult)
+        {
+            // return vresult;
+            if (sc->fes)
+            {
+                assert(rs->caseDim == 0);
+                sc->fes->cases->push(rs);
+                result = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1));
+                return;
+            }
+            if (fd->returnLabel)
+            {
+                GotoStatement *gs = new GotoStatement(rs->loc, Id::returnLabel);
+                gs->label = fd->returnLabel;
+                result = gs;
+                return;
+            }
+
+            if (!fd->returns)
+                fd->returns = new ReturnStatements();
+            fd->returns->push(rs);
+            result = rs;
+            return;
+        }
+
+        Type *tret = tf->next;
+        Type *tbret = tret ? tret->toBasetype() : NULL;
+
+        bool inferRef = (tf->isref && (fd->storage_class & STCauto));
+        Expression *e0 = NULL;
+
+        bool errors = false;
+        if (sc->flags & SCOPEcontract)
+        {
+            rs->error("return statements cannot be in contracts");
+            errors = true;
+        }
+        if (sc->os && sc->os->tok != TOKon_scope_failure)
+        {
+            rs->error("return statements cannot be in %s bodies", Token::toChars(sc->os->tok));
+            errors = true;
+        }
+        if (sc->tf)
+        {
+            rs->error("return statements cannot be in finally bodies");
+            errors = true;
+        }
+
+        if (fd->isCtorDeclaration())
+        {
+            if (rs->exp)
+            {
+                rs->error("cannot return expression from constructor");
+                errors = true;
+            }
+
+            // Constructors implicitly do:
+            //      return this;
+            rs->exp = new ThisExp(Loc());
+            rs->exp->type = tret;
+        }
+        else if (rs->exp)
+        {
+            fd->hasReturnExp |= (fd->hasReturnExp & 1 ? 16 : 1);
+
+            FuncLiteralDeclaration *fld = fd->isFuncLiteralDeclaration();
+            if (tret)
+                rs->exp = inferType(rs->exp, tret);
+            else if (fld && fld->treq)
+                rs->exp = inferType(rs->exp, fld->treq->nextOf()->nextOf());
+            rs->exp = semantic(rs->exp, sc);
+
+            // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+            if (rs->exp->op == TOKtype)
+                rs->exp = resolveAliasThis(sc, rs->exp);
+
+            rs->exp = resolveProperties(sc, rs->exp);
+            if (rs->exp->checkType())
+                rs->exp = new ErrorExp();
+            if (FuncDeclaration *f = isFuncAddress(rs->exp))
+            {
+                if (fd->inferRetType && f->checkForwardRef(rs->exp->loc))
+                    rs->exp = new ErrorExp();
+            }
+            if (checkNonAssignmentArrayOp(rs->exp))
+                rs->exp = new ErrorExp();
+
+            // Extract side-effect part
+            rs->exp = Expression::extractLast(rs->exp, &e0);
+            if (rs->exp->op == TOKcall)
+                rs->exp = valueNoDtor(rs->exp);
+
+            if (e0)
+                e0 = e0->optimize(WANTvalue);
+
+            /* Void-return function can have void typed expression
+             * on return statement.
+             */
+            if (tbret && tbret->ty == Tvoid || rs->exp->type->ty == Tvoid)
+            {
+                if (rs->exp->type->ty != Tvoid)
+                {
+                    rs->error("cannot return non-void from void function");
+                    errors = true;
+
+                    rs->exp = new CastExp(rs->loc, rs->exp, Type::tvoid);
+                    rs->exp = semantic(rs->exp, sc);
+                }
+
+                /* Replace:
+                 *      return exp;
+                 * with:
+                 *      exp; return;
+                 */
+                e0 = Expression::combine(e0, rs->exp);
+                rs->exp = NULL;
+            }
+            if (e0)
+                e0 = checkGC(sc, e0);
+        }
+
+        if (rs->exp)
+        {
+            if (fd->inferRetType)       // infer return type
+            {
+                if (!tret)
+                {
+                    tf->next = rs->exp->type;
+                }
+                else if (tret->ty != Terror && !rs->exp->type->equals(tret))
+                {
+                    int m1 = rs->exp->type->implicitConvTo(tret);
+                    int m2 = tret->implicitConvTo(rs->exp->type);
+                    //printf("exp->type = %s m2<-->m1 tret %s\n", rs->exp->type->toChars(), tret->toChars());
+                    //printf("m1 = %d, m2 = %d\n", m1, m2);
+
+                    if (m1 && m2)
+                        ;
+                    else if (!m1 && m2)
+                        tf->next = rs->exp->type;
+                    else if (m1 && !m2)
+                        ;
+                    else if (rs->exp->op != TOKerror)
+                    {
+                        rs->error("mismatched function return type inference of %s and %s",
+                                  rs->exp->type->toChars(), tret->toChars());
+                        errors = true;
+                        tf->next = Type::terror;
+                    }
+                }
+
+                tret = tf->next;
+                tbret = tret->toBasetype();
+            }
+
+            if (inferRef)               // deduce 'auto ref'
+            {
+                /* Determine "refness" of function return:
+                 * if it's an lvalue, return by ref, else return by value
+                 */
+                if (rs->exp->isLvalue())
+                {
+                    /* May return by ref
+                    */
+                    if (checkEscapeRef(sc, rs->exp, true))
+                        tf->isref = false;  // return by value
+                }
+                else
+                    tf->isref = false;      // return by value
+
+                /* The "refness" is determined by all of return statements.
+                 * This means:
+                 *    return 3; return x;  // ok, x can be a value
+                 *    return x; return 3;  // ok, x can be a value
+                 */
+            }
+
+            // handle NRVO
+            if (fd->nrvo_can && rs->exp->op == TOKvar)
+            {
+                VarExp *ve = (VarExp *)rs->exp;
+                VarDeclaration *v = ve->var->isVarDeclaration();
+
+                if (tf->isref)
+                {
+                    // Function returns a reference
+                    if (!inferRef)
+                        fd->nrvo_can = 0;
+                }
+                else if (!v || v->isOut() || v->isRef())
+                    fd->nrvo_can = 0;
+                else if (fd->nrvo_var == NULL)
+                {
+                    if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
+                    {
+                        //printf("Setting nrvo to %s\n", v->toChars());
+                        fd->nrvo_var = v;
+                    }
+                    else
+                        fd->nrvo_can = 0;
+                }
+                else if (fd->nrvo_var != v)
+                    fd->nrvo_can = 0;
+            }
+            else //if (!exp->isLvalue())    // keep NRVO-ability
+                fd->nrvo_can = 0;
+        }
+        else
+        {
+            // handle NRVO
+            fd->nrvo_can = 0;
+
+            // infer return type
+            if (fd->inferRetType)
+            {
+                if (tf->next && tf->next->ty != Tvoid)
+                {
+                    if (tf->next->ty != Terror)
+                    {
+                        rs->error("mismatched function return type inference of void and %s",
+                                  tf->next->toChars());
+                    }
+                    errors = true;
+                    tf->next = Type::terror;
+                }
+                else
+                    tf->next = Type::tvoid;
+
+                tret = tf->next;
+                tbret = tret->toBasetype();
+            }
+
+            if (inferRef)               // deduce 'auto ref'
+                tf->isref = false;
+
+            if (tbret->ty != Tvoid)     // if non-void return
+            {
+                if (tbret->ty != Terror)
+                    rs->error("return expression expected");
+                errors = true;
+            }
+            else if (fd->isMain())
+            {
+                // main() returns 0, even if it returns void
+                rs->exp = new IntegerExp(0);
+            }
+        }
+
+        // If any branches have called a ctor, but this branch hasn't, it's an error
+        if (sc->callSuper & CSXany_ctor &&
+            !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
+        {
+            rs->error("return without calling constructor");
+            errors = true;
+        }
+        sc->callSuper |= CSXreturn;
+        if (sc->fieldinit)
+        {
+            AggregateDeclaration *ad = fd->isMember2();
+            assert(ad);
+            size_t dim = sc->fieldinit_dim;
+            for (size_t i = 0; i < dim; i++)
+            {
+                VarDeclaration *v = ad->fields[i];
+                bool mustInit = (v->storage_class & STCnodefaultctor ||
+                                 v->type->needsNested());
+                if (mustInit && !(sc->fieldinit[i] & CSXthis_ctor))
+                {
+                    rs->error("an earlier return statement skips field %s initialization", v->toChars());
+                    errors = true;
+                }
+                sc->fieldinit[i] |= CSXreturn;
+            }
+        }
+
+        if (errors)
+            return setError();
+
+        if (sc->fes)
+        {
+            if (!rs->exp)
+            {
+                // Send out "case receiver" statement to the foreach.
+                //  return exp;
+                Statement *s = new ReturnStatement(Loc(), rs->exp);
+                sc->fes->cases->push(s);
+
+                // Immediately rewrite "this" return statement as:
+                //  return cases->dim+1;
+                rs->exp = new IntegerExp(sc->fes->cases->dim + 1);
+                if (e0)
+                {
+                    result = new CompoundStatement(rs->loc, new ExpStatement(rs->loc, e0), rs);
+                    return;
+                }
+                result = rs;
+                return;
+            }
+            else
+            {
+                fd->buildResultVar(NULL, rs->exp->type);
+                bool r = fd->vresult->checkNestedReference(sc, Loc());
+                assert(!r);  // vresult should be always accessible
+
+                // Send out "case receiver" statement to the foreach.
+                //  return vresult;
+                Statement *s = new ReturnStatement(Loc(), new VarExp(Loc(), fd->vresult));
+                sc->fes->cases->push(s);
+
+                // Save receiver index for the later rewriting from:
+                //  return exp;
+                // to:
+                //  vresult = exp; retrun caseDim;
+                rs->caseDim = sc->fes->cases->dim + 1;
+            }
+        }
+        if (rs->exp)
+        {
+            if (!fd->returns)
+                fd->returns = new ReturnStatements();
+            fd->returns->push(rs);
+        }
+        if (e0)
+        {
+            result = new CompoundStatement(rs->loc, new ExpStatement(rs->loc, e0), rs);
+            return;
+        }
+        result = rs;
+    }
+
+    void visit(BreakStatement *bs)
+    {
+        //printf("BreakStatement::semantic()\n");
+        // If:
+        //  break Identifier;
+        if (bs->ident)
+        {
+            bs->ident = fixupLabelName(sc, bs->ident);
+
+            FuncDeclaration *thisfunc = sc->func;
+
+            for (Scope *scx = sc; scx; scx = scx->enclosing)
+            {
+                if (scx->func != thisfunc)  // if in enclosing function
+                {
+                    if (sc->fes)            // if this is the body of a foreach
+                    {
+                        /* Post this statement to the fes, and replace
+                         * it with a return value that caller will put into
+                         * a switch. Caller will figure out where the break
+                         * label actually is.
+                         * Case numbers start with 2, not 0, as 0 is continue
+                         * and 1 is break.
+                         */
+                        sc->fes->cases->push(bs);
+                        result = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1));
+                        return;
+                    }
+                    break;                  // can't break to it
+                }
+
+                LabelStatement *ls = scx->slabel;
+                if (ls && ls->ident == bs->ident)
+                {
+                    Statement *s = ls->statement;
+
+                    if (!s || !s->hasBreak())
+                        bs->error("label '%s' has no break", bs->ident->toChars());
+                    else if (ls->tf != sc->tf)
+                        bs->error("cannot break out of finally block");
+                    else
+                    {
+                        ls->breaks = true;
+                        result = bs;
+                        return;
+                    }
+                    return setError();
+                }
+            }
+            bs->error("enclosing label '%s' for break not found", bs->ident->toChars());
+            return setError();
+        }
+        else if (!sc->sbreak)
+        {
+            if (sc->os && sc->os->tok != TOKon_scope_failure)
+            {
+                bs->error("break is not inside %s bodies", Token::toChars(sc->os->tok));
+            }
+            else if (sc->fes)
+            {
+                // Replace break; with return 1;
+                result = new ReturnStatement(Loc(), new IntegerExp(1));
+                return;
+            }
+            else
+                bs->error("break is not inside a loop or switch");
+            return setError();
+        }
+        result = bs;
+    }
+
+    void visit(ContinueStatement *cs)
+    {
+        //printf("ContinueStatement::semantic() %p\n", cs);
+        if (cs->ident)
+        {
+            cs->ident = fixupLabelName(sc, cs->ident);
+
+            Scope *scx;
+            FuncDeclaration *thisfunc = sc->func;
+
+            for (scx = sc; scx; scx = scx->enclosing)
+            {
+                LabelStatement *ls;
+
+                if (scx->func != thisfunc)  // if in enclosing function
+                {
+                    if (sc->fes)            // if this is the body of a foreach
+                    {
+                        for (; scx; scx = scx->enclosing)
+                        {
+                            ls = scx->slabel;
+                            if (ls && ls->ident == cs->ident && ls->statement == sc->fes)
+                            {
+                                // Replace continue ident; with return 0;
+                                result = new ReturnStatement(Loc(), new IntegerExp(0));
+                                return;
+                            }
+                        }
+
+                        /* Post this statement to the fes, and replace
+                         * it with a return value that caller will put into
+                         * a switch. Caller will figure out where the break
+                         * label actually is.
+                         * Case numbers start with 2, not 0, as 0 is continue
+                         * and 1 is break.
+                         */
+                        sc->fes->cases->push(cs);
+                        result = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1));
+                        return;
+                    }
+                    break;                  // can't continue to it
+                }
+
+                ls = scx->slabel;
+                if (ls && ls->ident == cs->ident)
+                {
+                    Statement *s = ls->statement;
+
+                    if (!s || !s->hasContinue())
+                        cs->error("label '%s' has no continue", cs->ident->toChars());
+                    else if (ls->tf != sc->tf)
+                        cs->error("cannot continue out of finally block");
+                    else
+                    {
+                        result = cs;
+                        return;
+                    }
+                    return setError();
+                }
+            }
+            cs->error("enclosing label '%s' for continue not found", cs->ident->toChars());
+            return setError();
+        }
+        else if (!sc->scontinue)
+        {
+            if (sc->os && sc->os->tok != TOKon_scope_failure)
+            {
+                cs->error("continue is not inside %s bodies", Token::toChars(sc->os->tok));
+            }
+            else if (sc->fes)
+            {
+                // Replace continue; with return 0;
+                result = new ReturnStatement(Loc(), new IntegerExp(0));
+                return;
+            }
+            else
+                cs->error("continue is not inside a loop");
+            return setError();
+        }
+        result = cs;
+    }
+
+    void visit(SynchronizedStatement *ss)
+    {
+        if (ss->exp)
+        {
+            ss->exp = semantic(ss->exp, sc);
+            ss->exp = resolveProperties(sc, ss->exp);
+            ss->exp = ss->exp->optimize(WANTvalue);
+            ss->exp = checkGC(sc, ss->exp);
+            if (ss->exp->op == TOKerror)
+                goto Lbody;
+            ClassDeclaration *cd = ss->exp->type->isClassHandle();
+            if (!cd)
+            {
+                ss->error("can only synchronize on class objects, not '%s'", ss->exp->type->toChars());
+                return setError();
+            }
+            else if (cd->isInterfaceDeclaration())
+            {
+                /* Cast the interface to an object, as the object has the monitor,
+                 * not the interface.
+                 */
+                if (!ClassDeclaration::object)
+                {
+                    ss->error("missing or corrupt object.d");
+                    fatal();
+                }
+
+                Type *t = ClassDeclaration::object->type;
+                t = t->semantic(Loc(), sc)->toBasetype();
+                assert(t->ty == Tclass);
+
+                ss->exp = new CastExp(ss->loc, ss->exp, t);
+                ss->exp = semantic(ss->exp, sc);
+            }
+
+#if 1
+            /* Rewrite as:
+             *  auto tmp = exp;
+             *  _d_monitorenter(tmp);
+             *  try { body } finally { _d_monitorexit(tmp); }
+             */
+            VarDeclaration *tmp = copyToTemp(0, "__sync", ss->exp);
+
+            Statements *cs = new Statements();
+            cs->push(new ExpStatement(ss->loc, tmp));
+
+            Parameters* args = new Parameters;
+            args->push(new Parameter(0, ClassDeclaration::object->type, NULL, NULL));
+
+            FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter);
+            Expression *e = new CallExp(ss->loc, new VarExp(ss->loc, fdenter, false), new VarExp(ss->loc, tmp));
+            e->type = Type::tvoid;                  // do not run semantic on e
+            cs->push(new ExpStatement(ss->loc, e));
+
+            FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorexit);
+            e = new CallExp(ss->loc, new VarExp(ss->loc, fdexit, false), new VarExp(ss->loc, tmp));
+            e->type = Type::tvoid;                  // do not run semantic on e
+            Statement *s = new ExpStatement(ss->loc, e);
+            s = new TryFinallyStatement(ss->loc, ss->_body, s);
+            cs->push(s);
+
+            s = new CompoundStatement(ss->loc, cs);
+            result = semantic(s, sc);
+            return;
+#endif
+        }
+        else
+        {
+            /* Generate our own critical section, then rewrite as:
+             *  __gshared byte[CriticalSection.sizeof] critsec;
+             *  _d_criticalenter(critsec.ptr);
+             *  try { body } finally { _d_criticalexit(critsec.ptr); }
+             */
+            Identifier *id = Identifier::generateId("__critsec");
+            Type *t = Type::tint8->sarrayOf(Target::ptrsize + Target::critsecsize());
+            VarDeclaration *tmp = new VarDeclaration(ss->loc, t, id, NULL);
+            tmp->storage_class |= STCtemp | STCgshared | STCstatic;
+
+            Statements *cs = new Statements();
+            cs->push(new ExpStatement(ss->loc, tmp));
+
+            /* This is just a dummy variable for "goto skips declaration" error.
+             * Backend optimizer could remove this unused variable.
+             */
+            VarDeclaration *v = new VarDeclaration(ss->loc, Type::tvoidptr, Identifier::generateId("__sync"), NULL);
+            v->semantic(sc);
+            cs->push(new ExpStatement(ss->loc, v));
+
+            Parameters* args = new Parameters;
+            args->push(new Parameter(0, t->pointerTo(), NULL, NULL));
+
+            FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter, STCnothrow);
+            Expression *e = new DotIdExp(ss->loc, new VarExp(ss->loc, tmp), Id::ptr);
+            e = semantic(e, sc);
+            e = new CallExp(ss->loc, new VarExp(ss->loc, fdenter, false), e);
+            e->type = Type::tvoid;                  // do not run semantic on e
+            cs->push(new ExpStatement(ss->loc, e));
+
+            FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalexit, STCnothrow);
+            e = new DotIdExp(ss->loc, new VarExp(ss->loc, tmp), Id::ptr);
+            e = semantic(e, sc);
+            e = new CallExp(ss->loc, new VarExp(ss->loc, fdexit, false), e);
+            e->type = Type::tvoid;                  // do not run semantic on e
+            Statement *s = new ExpStatement(ss->loc, e);
+            s = new TryFinallyStatement(ss->loc, ss->_body, s);
+            cs->push(s);
+
+            s = new CompoundStatement(ss->loc, cs);
+            result = semantic(s, sc);
+            return;
+        }
+    Lbody:
+        if (ss->_body)
+            ss->_body = semantic(ss->_body, sc);
+        if (ss->_body && ss->_body->isErrorStatement())
+        {
+            result = ss->_body;
+            return;
+        }
+        result = ss;
+    }
+
+    void visit(WithStatement *ws)
+    {
+        ScopeDsymbol *sym;
+        Initializer *init;
+
+        //printf("WithStatement::semantic()\n");
+        ws->exp = semantic(ws->exp, sc);
+        ws->exp = resolveProperties(sc, ws->exp);
+        ws->exp = ws->exp->optimize(WANTvalue);
+        ws->exp = checkGC(sc, ws->exp);
+        if (ws->exp->op == TOKerror)
+            return setError();
+        if (ws->exp->op == TOKscope)
+        {
+            sym = new WithScopeSymbol(ws);
+            sym->parent = sc->scopesym;
+            sym->endlinnum = ws->endloc.linnum;
+        }
+        else if (ws->exp->op == TOKtype)
+        {
+            Dsymbol *s = ((TypeExp *)ws->exp)->type->toDsymbol(sc);
+            if (!s || !s->isScopeDsymbol())
+            {
+                ws->error("with type %s has no members", ws->exp->toChars());
+                return setError();
+            }
+            sym = new WithScopeSymbol(ws);
+            sym->parent = sc->scopesym;
+            sym->endlinnum = ws->endloc.linnum;
+        }
+        else
+        {
+            Type *t = ws->exp->type->toBasetype();
+
+            Expression *olde = ws->exp;
+            if (t->ty == Tpointer)
+            {
+                ws->exp = new PtrExp(ws->loc, ws->exp);
+                ws->exp = semantic(ws->exp, sc);
+                t = ws->exp->type->toBasetype();
+            }
+
+            assert(t);
+            t = t->toBasetype();
+            if (t->isClassHandle())
+            {
+                init = new ExpInitializer(ws->loc, ws->exp);
+                ws->wthis = new VarDeclaration(ws->loc, ws->exp->type, Id::withSym, init);
+                ws->wthis->semantic(sc);
+
+                sym = new WithScopeSymbol(ws);
+                sym->parent = sc->scopesym;
+                sym->endlinnum = ws->endloc.linnum;
+            }
+            else if (t->ty == Tstruct)
+            {
+                if (!ws->exp->isLvalue())
+                {
+                    /* Re-write to
+                     * {
+                     *   auto __withtmp = exp
+                     *   with(__withtmp)
+                     *   {
+                     *     ...
+                     *   }
+                     * }
+                     */
+                    VarDeclaration *tmp = copyToTemp(0, "__withtmp", ws->exp);
+                    ExpStatement *es = new ExpStatement(ws->loc, tmp);
+                    ws->exp = new VarExp(ws->loc, tmp);
+                    Statement *ss = new ScopeStatement(ws->loc, new CompoundStatement(ws->loc, es, ws), ws->endloc);
+                    result = semantic(ss, sc);
+                    return;
+                }
+                Expression *e = ws->exp->addressOf();
+                init = new ExpInitializer(ws->loc, e);
+                ws->wthis = new VarDeclaration(ws->loc, e->type, Id::withSym, init);
+                ws->wthis->semantic(sc);
+                sym = new WithScopeSymbol(ws);
+                // Need to set the scope to make use of resolveAliasThis
+                sym->setScope(sc);
+                sym->parent = sc->scopesym;
+                sym->endlinnum = ws->endloc.linnum;
+            }
+            else
+            {
+                ws->error("with expressions must be aggregate types or pointers to them, not '%s'", olde->type->toChars());
+                return setError();
+            }
+        }
+
+        if (ws->_body)
+        {
+            sym->_scope = sc;
+            sc = sc->push(sym);
+            sc->insert(sym);
+            ws->_body = semantic(ws->_body, sc);
+            sc->pop();
+            if (ws->_body && ws->_body->isErrorStatement())
+            {
+                result = ws->_body;
+                return;
+            }
+        }
+
+        result = ws;
+    }
+
+    void visit(TryCatchStatement *tcs)
+    {
+        unsigned flags = 0;
+        const unsigned FLAGcpp = 1;
+        const unsigned FLAGd = 2;
+
+        tcs->_body = semanticScope(tcs->_body, sc, NULL, NULL);
+        assert(tcs->_body);
+
+        /* Even if body is empty, still do semantic analysis on catches
+        */
+        bool catchErrors = false;
+        for (size_t i = 0; i < tcs->catches->dim; i++)
+        {
+            Catch *c = (*tcs->catches)[i];
+            semantic(c, sc);
+            if (c->errors)
+            {
+                catchErrors = true;
+                continue;
+            }
+            ClassDeclaration *cd = c->type->toBasetype()->isClassHandle();
+            flags |= cd->isCPPclass() ? FLAGcpp : FLAGd;
+
+            // Determine if current catch 'hides' any previous catches
+            for (size_t j = 0; j < i; j++)
+            {
+                Catch *cj = (*tcs->catches)[j];
+                const char *si = c->loc.toChars();
+                const char *sj = cj->loc.toChars();
+
+                if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
+                {
+                    tcs->error("catch at %s hides catch at %s", sj, si);
+                    catchErrors = true;
+                }
+            }
+        }
+
+        if (sc->func)
+        {
+            if (flags == (FLAGcpp | FLAGd))
+            {
+                tcs->error("cannot mix catching D and C++ exceptions in the same try-catch");
+                catchErrors = true;
+            }
+        }
+
+        if (catchErrors)
+            return setError();
+
+        if (tcs->_body->isErrorStatement())
+        {
+            result = tcs->_body;
+            return;
+        }
+
+        /* If the try body never throws, we can eliminate any catches
+         * of recoverable exceptions.
+         */
+
+        if (!(blockExit(tcs->_body, sc->func, false) & BEthrow) && ClassDeclaration::exception)
+        {
+            for (size_t i = 0; i < tcs->catches->dim; i++)
+            {
+                Catch *c = (*tcs->catches)[i];
+
+                /* If catch exception type is derived from Exception
+                */
+                if (c->type->toBasetype()->implicitConvTo(ClassDeclaration::exception->type) &&
+                    (!c->handler || !c->handler->comeFrom()))
+                {
+                    // Remove c from the array of catches
+                    tcs->catches->remove(i);
+                    --i;
+                }
+            }
+        }
+
+        if (tcs->catches->dim == 0)
+        {
+            result = tcs->_body->hasCode() ? tcs->_body : NULL;
+            return;
+        }
+
+        result = tcs;
+    }
+
+    void visit(TryFinallyStatement *tfs)
+    {
+        //printf("TryFinallyStatement::semantic()\n");
+        tfs->_body = semantic(tfs->_body, sc);
+        sc = sc->push();
+        sc->tf = tfs;
+        sc->sbreak = NULL;
+        sc->scontinue = NULL;       // no break or continue out of finally block
+        tfs->finalbody = semanticNoScope(tfs->finalbody, sc);
+        sc->pop();
+
+        if (!tfs->_body)
+        {
+            result = tfs->finalbody;
+            return;
+        }
+
+        if (!tfs->finalbody)
+        {
+            result = tfs->_body;
+            return;
+        }
+
+        if (blockExit(tfs->_body, sc->func, false) == BEfallthru)
+        {
+            result = new CompoundStatement(tfs->loc, tfs->_body, tfs->finalbody);
+            return;
+        }
+        result = tfs;
+    }
+
+    void visit(OnScopeStatement *oss)
+    {
+#ifndef IN_GCC
+        if (oss->tok != TOKon_scope_exit)
+        {
+            // scope(success) and scope(failure) are rewritten to try-catch(-finally) statement,
+            // so the generated catch block cannot be placed in finally block.
+            // See also Catch::semantic.
+            if (sc->os && sc->os->tok != TOKon_scope_failure)
+            {
+                // If enclosing is scope(success) or scope(exit), this will be placed in finally block.
+                oss->error("cannot put %s statement inside %s", Token::toChars(oss->tok), Token::toChars(sc->os->tok));
+                return setError();
+            }
+            if (sc->tf)
+            {
+                oss->error("cannot put %s statement inside finally block", Token::toChars(oss->tok));
+                return setError();
+            }
+        }
+#endif
+
+        sc = sc->push();
+        sc->tf = NULL;
+        sc->os = oss;
+        if (oss->tok != TOKon_scope_failure)
+        {
+            // Jump out from scope(failure) block is allowed.
+            sc->sbreak = NULL;
+            sc->scontinue = NULL;
+        }
+        oss->statement = semanticNoScope(oss->statement, sc);
+        sc->pop();
+
+        if (!oss->statement || oss->statement->isErrorStatement())
+        {
+            result = oss->statement;
+            return;
+        }
+        result = oss;
+    }
+
+    void visit(ThrowStatement *ts)
+    {
+        //printf("ThrowStatement::semantic()\n");
+
+        FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+        fd->hasReturnExp |= 2;
+
+        ts->exp = semantic(ts->exp, sc);
+        ts->exp = resolveProperties(sc, ts->exp);
+        ts->exp = checkGC(sc, ts->exp);
+        if (ts->exp->op == TOKerror)
+            return setError();
+
+        ClassDeclaration *cd = ts->exp->type->toBasetype()->isClassHandle();
+        if (!cd || ((cd != ClassDeclaration::throwable) && !ClassDeclaration::throwable->isBaseOf(cd, NULL)))
+        {
+            ts->error("can only throw class objects derived from Throwable, not type %s", ts->exp->type->toChars());
+            return setError();
+        }
+
+        result = ts;
+    }
+
+    void visit(DebugStatement *ds)
+    {
+        if (ds->statement)
+        {
+            sc = sc->push();
+            sc->flags |= SCOPEdebug;
+            ds->statement = semantic(ds->statement, sc);
+            sc->pop();
+        }
+        result = ds->statement;
+    }
+
+    void visit(GotoStatement *gs)
+    {
+        //printf("GotoStatement::semantic()\n");
+        FuncDeclaration *fd = sc->func;
+
+        gs->ident = fixupLabelName(sc, gs->ident);
+        gs->label = fd->searchLabel(gs->ident);
+        gs->tf = sc->tf;
+        gs->os = sc->os;
+        gs->lastVar = sc->lastVar;
+
+        if (!gs->label->statement && sc->fes)
+        {
+            /* Either the goto label is forward referenced or it
+             * is in the function that the enclosing foreach is in.
+             * Can't know yet, so wrap the goto in a scope statement
+             * so we can patch it later, and add it to a 'look at this later'
+             * list.
+             */
+            ScopeStatement *ss = new ScopeStatement(gs->loc, gs, gs->loc);
+            sc->fes->gotos->push(ss);       // 'look at this later' list
+            result = ss;
+            return;
+        }
+
+        // Add to fwdref list to check later
+        if (!gs->label->statement)
+        {
+            if (!fd->gotos)
+                fd->gotos = new GotoStatements();
+            fd->gotos->push(gs);
+        }
+        else if (gs->checkLabel())
+            return setError();
+
+        result = gs;
+    }
+
+    void visit(LabelStatement *ls)
+    {
+        //printf("LabelStatement::semantic()\n");
+        FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+
+        ls->ident = fixupLabelName(sc, ls->ident);
+        ls->tf = sc->tf;
+        ls->os = sc->os;
+        ls->lastVar = sc->lastVar;
+
+        LabelDsymbol *ls2 = fd->searchLabel(ls->ident);
+        if (ls2->statement)
+        {
+            ls->error("label '%s' already defined", ls2->toChars());
+            return setError();
+        }
+        else
+            ls2->statement = ls;
+
+        sc = sc->push();
+        sc->scopesym = sc->enclosing->scopesym;
+        sc->callSuper |= CSXlabel;
+        if (sc->fieldinit)
+        {
+            size_t dim = sc->fieldinit_dim;
+            for (size_t i = 0; i < dim; i++)
+                sc->fieldinit[i] |= CSXlabel;
+        }
+        sc->slabel = ls;
+        if (ls->statement)
+            ls->statement = semantic(ls->statement, sc);
+        sc->pop();
+
+        result = ls;
+    }
+
+    void visit(AsmStatement *s)
+    {
+        result = asmSemantic(s, sc);
+    }
+
+#ifdef IN_GCC
+    void visit(ExtAsmStatement *s)
+    {
+        // Fold the instruction template string.
+        s->insn = semantic(s->insn, sc);
+        s->insn->ctfeInterpret();
+
+        if (s->insn->op != TOKstring || ((StringExp *) s->insn)->sz != 1)
+            s->insn->error("instruction template must be a constant char string");
+
+        if (s->labels && s->outputargs)
+            s->error("extended asm statements with labels cannot have output constraints");
+
+        // Analyse all input and output operands.
+        if (s->args)
+        {
+            for (size_t i = 0; i < s->args->dim; i++)
+            {
+                Expression *e = (*s->args)[i];
+                e = semantic(e, sc);
+                // Check argument is a valid lvalue/rvalue.
+                if (i < s->outputargs)
+                    e = e->modifiableLvalue(sc, NULL);
+                else if (e->checkValue())
+                    e = new ErrorExp();
+                (*s->args)[i] = e;
+
+                e = (*s->constraints)[i];
+                e = semantic(e, sc);
+                assert(e->op == TOKstring && ((StringExp *) e)->sz == 1);
+                (*s->constraints)[i] = e;
+            }
+        }
+
+        // Analyse all clobbers.
+        if (s->clobbers)
+        {
+            for (size_t i = 0; i < s->clobbers->dim; i++)
+            {
+                Expression *e = (*s->clobbers)[i];
+                e = semantic(e, sc);
+                assert(e->op == TOKstring && ((StringExp *) e)->sz == 1);
+                (*s->clobbers)[i] = e;
+            }
+        }
+
+        // Analyse all goto labels.
+        if (s->labels)
+        {
+            for (size_t i = 0; i < s->labels->dim; i++)
+            {
+                Identifier *ident = (*s->labels)[i];
+                GotoStatement *gs = new GotoStatement(s->loc, ident);
+                if (!s->gotos)
+                    s->gotos = new GotoStatements();
+                s->gotos->push(gs);
+                semantic(gs, sc);
+            }
+        }
+
+        result = s;
+    }
+#endif
+
+    void visit(CompoundAsmStatement *cas)
+    {
+        for (size_t i = 0; i < cas->statements->dim; i++)
+        {
+            Statement *s = (*cas->statements)[i];
+            (*cas->statements)[i] = s ? semantic(s, sc) : NULL;
+        }
+
+        assert(sc->func);
+        // use setImpure/setGC when the deprecation cycle is over
+        PURE purity;
+        if (!(cas->stc & STCpure) && (purity = sc->func->isPureBypassingInference()) != PUREimpure && purity != PUREfwdref)
+            cas->deprecation("asm statement is assumed to be impure - mark it with 'pure' if it is not");
+        if (!(cas->stc & STCnogc) && sc->func->isNogcBypassingInference())
+            cas->deprecation("asm statement is assumed to use the GC - mark it with '@nogc' if it does not");
+        if (!(cas->stc & (STCtrusted|STCsafe)) && sc->func->setUnsafe())
+            cas->error("asm statement is assumed to be @system - mark it with '@trusted' if it is not");
+
+        result = cas;
+    }
+
+    void visit(ImportStatement *imps)
+    {
+        for (size_t i = 0; i < imps->imports->dim; i++)
+        {
+            Import *s = (*imps->imports)[i]->isImport();
+            assert(!s->aliasdecls.dim);
+            for (size_t j = 0; j < s->names.dim; j++)
+            {
+                Identifier *name = s->names[j];
+                Identifier *alias = s->aliases[j];
+
+                if (!alias)
+                    alias = name;
+
+                TypeIdentifier *tname = new TypeIdentifier(s->loc, name);
+                AliasDeclaration *ad = new AliasDeclaration(s->loc, alias, tname);
+                ad->_import = s;
+                s->aliasdecls.push(ad);
+            }
+
+            s->semantic(sc);
+            Module::addDeferredSemantic2(s);     // Bugzilla 14666
+            sc->insert(s);
+
+            for (size_t j = 0; j < s->aliasdecls.dim; j++)
+            {
+                sc->insert(s->aliasdecls[j]);
+            }
+        }
+        result = imps;
+    }
+};
+
+Statement *semantic(Statement *s, Scope *sc)
+{
+    StatementSemanticVisitor v = StatementSemanticVisitor(sc);
+    s->accept(&v);
+    return v.result;
+}
+
+void semantic(Catch *c, Scope *sc)
+{
+    //printf("Catch::semantic(%s)\n", ident->toChars());
+
+#ifndef IN_GCC
+    if (sc->os && sc->os->tok != TOKon_scope_failure)
+    {
+        // If enclosing is scope(success) or scope(exit), this will be placed in finally block.
+        error(c->loc, "cannot put catch statement inside %s", Token::toChars(sc->os->tok));
+        c->errors = true;
+    }
+    if (sc->tf)
+    {
+        /* This is because the _d_local_unwind() gets the stack munged
+         * up on this. The workaround is to place any try-catches into
+         * a separate function, and call that.
+         * To fix, have the compiler automatically convert the finally
+         * body into a nested function.
+         */
+        error(c->loc, "cannot put catch statement inside finally block");
+        c->errors = true;
+    }
+#endif
+
+    ScopeDsymbol *sym = new ScopeDsymbol();
+    sym->parent = sc->scopesym;
+    sc = sc->push(sym);
+
+    if (!c->type)
+    {
+        // reference .object.Throwable
+        TypeIdentifier *tid = new TypeIdentifier(Loc(), Id::empty);
+        tid->addIdent(Id::object);
+        tid->addIdent(Id::Throwable);
+        c->type = tid;
+    }
+    c->type = c->type->semantic(c->loc, sc);
+    if (c->type == Type::terror)
+        c->errors = true;
+    else
+    {
+        ClassDeclaration *cd = c->type->toBasetype()->isClassHandle();
+        if (!cd)
+        {
+            error(c->loc, "can only catch class objects, not '%s'", c->type->toChars());
+            c->errors = true;
+        }
+        else if (cd->isCPPclass())
+        {
+            if (!Target::cppExceptions)
+            {
+                error(c->loc, "catching C++ class objects not supported for this target");
+                c->errors = true;
+            }
+            if (sc->func && !sc->intypeof && !c->internalCatch && sc->func->setUnsafe())
+            {
+                error(c->loc, "cannot catch C++ class objects in @safe code");
+                c->errors = true;
+            }
+        }
+        else if (cd != ClassDeclaration::throwable && !ClassDeclaration::throwable->isBaseOf(cd, NULL))
+        {
+            error(c->loc, "can only catch class objects derived from Throwable, not '%s'", c->type->toChars());
+            c->errors = true;
+        }
+        else if (sc->func && !sc->intypeof && !c->internalCatch &&
+                 cd != ClassDeclaration::exception && !ClassDeclaration::exception->isBaseOf(cd, NULL) &&
+                 sc->func->setUnsafe())
+        {
+            error(c->loc, "can only catch class objects derived from Exception in @safe code, not '%s'", c->type->toChars());
+            c->errors = true;
+        }
+
+        if (c->ident)
+        {
+            c->var = new VarDeclaration(c->loc, c->type, c->ident, NULL);
+            c->var->semantic(sc);
+            sc->insert(c->var);
+        }
+        c->handler = semantic(c->handler, sc);
+        if (c->handler && c->handler->isErrorStatement())
+            c->errors = true;
+    }
+    sc->pop();
+}
+
+Statement *semanticNoScope(Statement *s, Scope *sc)
+{
+    //printf("Statement::semanticNoScope() %s\n", toChars());
+    if (!s->isCompoundStatement() && !s->isScopeStatement())
+    {
+        s = new CompoundStatement(s->loc, s); // so scopeCode() gets called
+    }
+    s = semantic(s, sc);
+    return s;
+}
+
+// Same as semanticNoScope(), but do create a new scope
+Statement *semanticScope(Statement *s, Scope *sc, Statement *sbreak, Statement *scontinue)
+{
+    ScopeDsymbol *sym = new ScopeDsymbol();
+    sym->parent = sc->scopesym;
+    Scope *scd = sc->push(sym);
+    if (sbreak)
+        scd->sbreak = sbreak;
+    if (scontinue)
+        scd->scontinue = scontinue;
+    s = semanticNoScope(s, scd);
+    scd->pop();
+    return s;
+}
diff --git a/gcc/d/dfrontend/staticassert.c b/gcc/d/dfrontend/staticassert.c
new file mode 100644
index 00000000000..c44706c107f
--- /dev/null
+++ b/gcc/d/dfrontend/staticassert.c
@@ -0,0 +1,104 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/staticassert.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "dsymbol.h"
+#include "staticassert.h"
+#include "expression.h"
+#include "id.h"
+#include "scope.h"
+#include "template.h"
+#include "declaration.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
+
+/********************************* AttribDeclaration ****************************/
+
+StaticAssert::StaticAssert(Loc loc, Expression *exp, Expression *msg)
+        : Dsymbol(Id::empty)
+{
+    this->loc = loc;
+    this->exp = exp;
+    this->msg = msg;
+}
+
+Dsymbol *StaticAssert::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    return new StaticAssert(loc, exp->syntaxCopy(), msg ? msg->syntaxCopy() : NULL);
+}
+
+void StaticAssert::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+    // we didn't add anything
+}
+
+void StaticAssert::semantic(Scope *sc)
+{
+}
+
+void StaticAssert::semantic2(Scope *sc)
+{
+    //printf("StaticAssert::semantic2() %s\n", toChars());
+    ScopeDsymbol *sds = new ScopeDsymbol();
+    sc = sc->push(sds);
+    sc->tinst = NULL;
+    sc->minst = NULL;
+
+    bool errors = false;
+    bool result = evalStaticCondition(sc, exp, exp, errors);
+    sc = sc->pop();
+    if (errors)
+    {
+        errorSupplemental(loc, "while evaluating: static assert(%s)", exp->toChars());
+    }
+    else if (!result)
+    {
+        if (msg)
+        {
+            sc = sc->startCTFE();
+            msg = ::semantic(msg, sc);
+            msg = resolveProperties(sc, msg);
+            sc = sc->endCTFE();
+            msg = msg->ctfeInterpret();
+            if (StringExp * se = msg->toStringExp())
+            {
+                // same with pragma(msg)
+                se = se->toUTF8(sc);
+                error("\"%.*s\"", (int)se->len, (char *)se->string);
+            }
+            else
+                error("%s", msg->toChars());
+        }
+        else
+            error("(%s) is false", exp->toChars());
+        if (sc->tinst)
+            sc->tinst->printInstantiationTrace();
+        if (!global.gag)
+              fatal();
+    }
+}
+
+bool StaticAssert::oneMember(Dsymbol **ps, Identifier *ident)
+{
+    //printf("StaticAssert::oneMember())\n");
+    *ps = NULL;
+    return true;
+}
+
+const char *StaticAssert::kind()
+{
+    return "static assert";
+}
diff --git a/gcc/d/dfrontend/staticassert.h b/gcc/d/dfrontend/staticassert.h
new file mode 100644
index 00000000000..b68b91dd59b
--- /dev/null
+++ b/gcc/d/dfrontend/staticassert.h
@@ -0,0 +1,40 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/staticassert.h
+ */
+
+#ifndef DMD_STATICASSERT_H
+#define DMD_STATICASSERT_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+
+class Expression;
+
+class StaticAssert : public Dsymbol
+{
+public:
+    Expression *exp;
+    Expression *msg;
+
+    StaticAssert(Loc loc, Expression *exp, Expression *msg);
+
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void addMember(Scope *sc, ScopeDsymbol *sds);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    bool oneMember(Dsymbol **ps, Identifier *ident);
+    const char *kind();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#endif
diff --git a/gcc/d/dfrontend/staticcond.c b/gcc/d/dfrontend/staticcond.c
new file mode 100644
index 00000000000..f1c14e1c10e
--- /dev/null
+++ b/gcc/d/dfrontend/staticcond.c
@@ -0,0 +1,67 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2017 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/staticcond.c
+ */
+
+#include "expression.h"
+#include "mtype.h"
+#include "scope.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+
+/********************************************
+ * Semantically analyze and then evaluate a static condition at compile time.
+ * This is special because short circuit operators &&, || and ?: at the top
+ * level are not semantically analyzed if the result of the expression is not
+ * necessary.
+ * Params:
+ *      exp = original expression, for error messages
+ * Returns:
+ *      true if evaluates to true
+ */
+
+bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors)
+{
+    unsigned nerrors = global.errors;
+
+    sc = sc->startCTFE();
+    sc->flags |= SCOPEcondition;
+
+    e = semantic(e, sc);
+    e = resolveProperties(sc, e);
+
+    sc = sc->endCTFE();
+    e = e->optimize(WANTvalue);
+
+    if (nerrors != global.errors ||
+        e->op == TOKerror ||
+        e->type->toBasetype() == Type::terror)
+    {
+        errors = true;
+        return false;
+    }
+
+    if (!e->type->isBoolean())
+    {
+        exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars());
+        errors = true;
+        return false;
+    }
+
+    e = e->ctfeInterpret();
+
+    if (e->isBool(true))
+        return true;
+    else if (e->isBool(false))
+        return false;
+
+    e->error("expression %s is not constant", e->toChars());
+    errors = true;
+    return false;
+}
diff --git a/gcc/d/dfrontend/stringtable.c b/gcc/d/dfrontend/stringtable.c
new file mode 100644
index 00000000000..c4f0e2ca9fb
--- /dev/null
+++ b/gcc/d/dfrontend/stringtable.c
@@ -0,0 +1,201 @@
+
+/* Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/stringtable.c
+ */
+
+#include <stdio.h>
+#include <stdint.h>                     // uint{8|16|32}_t
+#include <string.h>                     // memcpy()
+#include <stdlib.h>
+
+#include "root.h"
+#include "rmem.h"                       // mem
+#include "stringtable.h"
+#include "hash.h"
+
+#define POOL_BITS 12
+#define POOL_SIZE (1U << POOL_BITS)
+
+struct StringEntry
+{
+    uint32_t hash;
+    uint32_t vptr;
+};
+
+uint32_t StringTable::allocValue(const char *s, size_t length, void *ptrvalue)
+{
+    const size_t nbytes = sizeof(StringValue) + length + 1;
+
+    if (!npools || nfill + nbytes > POOL_SIZE)
+    {
+        pools = (uint8_t **)mem.xrealloc(pools, ++npools * sizeof(pools[0]));
+        pools[npools - 1] = (uint8_t *)mem.xmalloc(nbytes > POOL_SIZE ? nbytes : POOL_SIZE);
+        nfill = 0;
+    }
+
+    StringValue *sv = (StringValue *)&pools[npools - 1][nfill];
+    sv->ptrvalue = ptrvalue;
+    sv->length = length;
+    ::memcpy(sv->lstring(), s, length);
+    sv->lstring()[length] = 0;
+
+    const uint32_t vptr = (uint32_t)(npools << POOL_BITS | nfill);
+    nfill += nbytes + (-nbytes & 7); // align to 8 bytes
+    return vptr;
+}
+
+StringValue *StringTable::getValue(uint32_t vptr)
+{
+    if (!vptr) return NULL;
+
+    const size_t idx = (vptr >> POOL_BITS) - 1;
+    const size_t off = vptr & POOL_SIZE - 1;
+    return (StringValue *)&pools[idx][off];
+}
+
+static size_t nextpow2(size_t val)
+{
+    size_t res = 1;
+    while (res < val)
+        res <<= 1;
+    return res;
+}
+
+static const double loadFactor = 0.8;
+
+void StringTable::_init(size_t size)
+{
+    size = nextpow2((size_t)(size / loadFactor));
+    if (size < 32) size = 32;
+    table = (StringEntry *)mem.xcalloc(size, sizeof(table[0]));
+    tabledim = size;
+    pools = NULL;
+    npools = nfill = 0;
+    count = 0;
+}
+
+void StringTable::reset(size_t size)
+{
+    for (size_t i = 0; i < npools; ++i)
+        mem.xfree(pools[i]);
+
+    mem.xfree(table);
+    mem.xfree(pools);
+    table = NULL;
+    pools = NULL;
+    _init(size);
+}
+
+StringTable::~StringTable()
+{
+    for (size_t i = 0; i < npools; ++i)
+        mem.xfree(pools[i]);
+
+    mem.xfree(table);
+    mem.xfree(pools);
+    table = NULL;
+    pools = NULL;
+}
+
+size_t StringTable::findSlot(hash_t hash, const char *s, size_t length)
+{
+    // quadratic probing using triangular numbers
+    // http://stackoverflow.com/questions/2348187/moving-from-linear-probing-to-quadratic-probing-hash-collisons/2349774#2349774
+    for (size_t i = hash & (tabledim - 1), j = 1; ;++j)
+    {
+        StringValue *sv;
+        if (!table[i].vptr ||
+            table[i].hash == hash &&
+            (sv = getValue(table[i].vptr))->length == length &&
+            ::memcmp(s, sv->lstring(), length) == 0)
+            return i;
+        i = (i + j) & (tabledim - 1);
+    }
+}
+
+StringValue *StringTable::lookup(const char *s, size_t length)
+{
+    const hash_t hash = calcHash(s, length);
+    const size_t i = findSlot(hash, s, length);
+    // printf("lookup %.*s %p\n", (int)length, s, table[i].value ?: NULL);
+    return getValue(table[i].vptr);
+}
+
+StringValue *StringTable::update(const char *s, size_t length)
+{
+    const hash_t hash = calcHash(s, length);
+    size_t i = findSlot(hash, s, length);
+    if (!table[i].vptr)
+    {
+        if (++count > tabledim * loadFactor)
+        {
+            grow();
+            i = findSlot(hash, s, length);
+        }
+        table[i].hash = hash;
+        table[i].vptr = allocValue(s, length, NULL);
+    }
+    // printf("update %.*s %p\n", (int)length, s, table[i].value ?: NULL);
+    return getValue(table[i].vptr);
+}
+
+StringValue *StringTable::insert(const char *s, size_t length, void *ptrvalue)
+{
+    const hash_t hash = calcHash(s, length);
+    size_t i = findSlot(hash, s, length);
+    if (table[i].vptr)
+        return NULL; // already in table
+    if (++count > tabledim * loadFactor)
+    {
+        grow();
+        i = findSlot(hash, s, length);
+    }
+    table[i].hash = hash;
+    table[i].vptr = allocValue(s, length, ptrvalue);
+    // printf("insert %.*s %p\n", (int)length, s, table[i].value ?: NULL);
+    return getValue(table[i].vptr);
+}
+
+void StringTable::grow()
+{
+    const size_t odim = tabledim;
+    StringEntry *otab = table;
+    tabledim *= 2;
+    table = (StringEntry *)mem.xcalloc(tabledim, sizeof(table[0]));
+
+    for (size_t i = 0; i < odim; ++i)
+    {
+        StringEntry *se = &otab[i];
+        if (!se->vptr) continue;
+        StringValue *sv = getValue(se->vptr);
+        table[findSlot(se->hash, sv->lstring(), sv->length)] = *se;
+    }
+    mem.xfree(otab);
+}
+
+/********************************
+ * Walk the contents of the string table,
+ * calling fp for each entry.
+ * Params:
+ *      fp = function to call. Returns !=0 to stop
+ * Returns:
+ *      last return value of fp call
+ */
+int StringTable::apply(int (*fp)(StringValue *))
+{
+    for (size_t i = 0; i < tabledim; ++i)
+    {
+        StringEntry *se = &table[i];
+        if (!se->vptr) continue;
+        StringValue *sv = getValue(se->vptr);
+        int result = (*fp)(sv);
+        if (result)
+            return result;
+    }
+    return 0;
+}
+
diff --git a/gcc/d/dfrontend/stringtable.h b/gcc/d/dfrontend/stringtable.h
new file mode 100644
index 00000000000..efbcc74d82c
--- /dev/null
+++ b/gcc/d/dfrontend/stringtable.h
@@ -0,0 +1,65 @@
+
+/* Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved, written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/dlang/dmd/blob/master/src/root/stringtable.h
+ */
+
+#ifndef STRINGTABLE_H
+#define STRINGTABLE_H
+
+#if __SC__
+#pragma once
+#endif
+
+#include "root.h"
+#include "rmem.h"   // for d_size_t
+
+struct StringEntry;
+
+// StringValue is a variable-length structure. It has neither proper c'tors nor a
+// factory method because the only thing which should be creating these is StringTable.
+struct StringValue
+{
+    void *ptrvalue;
+    size_t length;
+    char *lstring() { return (char *)(this + 1); }
+
+    size_t len() const { return length; }
+    const char *toDchars() const { return (const char *)(this + 1); }
+
+    StringValue();  // not constructible
+};
+
+struct StringTable
+{
+private:
+    StringEntry *table;
+    size_t tabledim;
+
+    uint8_t **pools;
+    size_t npools;
+    size_t nfill;
+
+    size_t count;
+
+public:
+    void _init(d_size_t size = 0);
+    void reset(d_size_t size = 0);
+    ~StringTable();
+
+    StringValue *lookup(const char *s, d_size_t len);
+    StringValue *insert(const char *s, size_t len, void *ptrvalue);
+    StringValue *update(const char *s, d_size_t len);
+    int apply(int (*fp)(StringValue *));
+
+private:
+    uint32_t allocValue(const char *p, size_t length, void *ptrvalue);
+    StringValue *getValue(uint32_t validx);
+    size_t findSlot(hash_t hash, const char *s, size_t len);
+    void grow();
+};
+
+#endif
diff --git a/gcc/d/dfrontend/target.h b/gcc/d/dfrontend/target.h
new file mode 100644
index 00000000000..e1c52d3e3e2
--- /dev/null
+++ b/gcc/d/dfrontend/target.h
@@ -0,0 +1,82 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 2013-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Iain Buclaw
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/target.h
+ */
+
+#ifndef TARGET_H
+#define TARGET_H
+
+// This file contains a data structure that describes a back-end target.
+// At present it is incomplete, but in future it should grow to contain
+// most or all target machine and target O/S specific information.
+#include "globals.h"
+#include "tokens.h"
+
+class ClassDeclaration;
+class Dsymbol;
+class Expression;
+class Type;
+class Module;
+struct OutBuffer;
+
+struct Target
+{
+    static int ptrsize;
+    static int realsize;             // size a real consumes in memory
+    static int realpad;              // 'padding' added to the CPU real size to bring it up to realsize
+    static int realalignsize;        // alignment for reals
+    static bool reverseCppOverloads; // with dmc and cl, overloaded functions are grouped and in reverse order
+    static bool cppExceptions;       // set if catching C++ exceptions is supported
+    static int c_longsize;           // size of a C 'long' or 'unsigned long' type
+    static int c_long_doublesize;    // size of a C 'long double'
+    static int classinfosize;        // size of 'ClassInfo'
+    static unsigned long long maxStaticDataSize;  // maximum size of static data
+
+    template <typename T>
+    struct FPTypeProperties
+    {
+        static real_t max;
+        static real_t min_normal;
+        static real_t nan;
+        static real_t snan;
+        static real_t infinity;
+        static real_t epsilon;
+
+        static d_int64 dig;
+        static d_int64 mant_dig;
+        static d_int64 max_exp;
+        static d_int64 min_exp;
+        static d_int64 max_10_exp;
+        static d_int64 min_10_exp;
+    };
+
+    typedef FPTypeProperties<float> FloatProperties;
+    typedef FPTypeProperties<double> DoubleProperties;
+    typedef FPTypeProperties<real_t> RealProperties;
+
+    static void _init();
+    // Type sizes and support.
+    static unsigned alignsize(Type* type);
+    static unsigned fieldalign(Type* type);
+    static unsigned critsecsize();
+    static Type *va_listType();  // get type of va_list
+    static int isVectorTypeSupported(int sz, Type *type);
+    static bool isVectorOpSupported(Type *type, TOK op, Type *t2 = NULL);
+    // CTFE support for cross-compilation.
+    static Expression *paintAsType(Expression *e, Type *type);
+    // ABI and backend.
+    static void loadModule(Module *m);
+    static void prefixName(OutBuffer *buf, LINK linkage);
+    static const char *toCppMangle(Dsymbol *s);
+    static const char *cppTypeInfoMangle(ClassDeclaration *cd);
+    static const char *cppTypeMangle(Type *t);
+    static LINK systemLinkage();
+};
+
+#endif
diff --git a/gcc/d/dfrontend/template.h b/gcc/d/dfrontend/template.h
new file mode 100644
index 00000000000..39ecdd0db49
--- /dev/null
+++ b/gcc/d/dfrontend/template.h
@@ -0,0 +1,402 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/template.h
+ */
+
+#ifndef DMD_TEMPLATE_H
+#define DMD_TEMPLATE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "arraytypes.h"
+#include "dsymbol.h"
+
+
+struct OutBuffer;
+class Identifier;
+class TemplateInstance;
+class TemplateParameter;
+class TemplateTypeParameter;
+class TemplateThisParameter;
+class TemplateValueParameter;
+class TemplateAliasParameter;
+class TemplateTupleParameter;
+class Type;
+class TypeQualified;
+class TypeTypeof;
+struct Scope;
+class Expression;
+class AliasDeclaration;
+class FuncDeclaration;
+class Parameter;
+enum MATCH;
+enum PASS;
+
+class Tuple : public RootObject
+{
+public:
+    Objects objects;
+
+    // kludge for template.isType()
+    int dyncast() const { return DYNCAST_TUPLE; }
+
+    const char *toChars() { return objects.toChars(); }
+};
+
+struct TemplatePrevious
+{
+    TemplatePrevious *prev;
+    Scope *sc;
+    Objects *dedargs;
+};
+
+class TemplateDeclaration : public ScopeDsymbol
+{
+public:
+    TemplateParameters *parameters;     // array of TemplateParameter's
+
+    TemplateParameters *origParameters; // originals for Ddoc
+    Expression *constraint;
+
+    // Hash table to look up TemplateInstance's of this TemplateDeclaration
+    void *instances;
+
+    TemplateDeclaration *overnext;      // next overloaded TemplateDeclaration
+    TemplateDeclaration *overroot;      // first in overnext list
+    FuncDeclaration *funcroot;          // first function in unified overload list
+
+    Dsymbol *onemember;         // if !=NULL then one member of this template
+
+    bool literal;               // this template declaration is a literal
+    bool ismixin;               // template declaration is only to be used as a mixin
+    bool isstatic;              // this is static template declaration
+    Prot protection;
+
+    TemplatePrevious *previous;         // threaded list of previous instantiation attempts on stack
+
+    TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters,
+        Expression *constraint, Dsymbols *decldefs, bool ismixin = false, bool literal = false);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    bool overloadInsert(Dsymbol *s);
+    bool hasStaticCtorOrDtor();
+    const char *kind();
+    const char *toChars();
+
+    Prot prot();
+
+    bool evaluateConstraint(TemplateInstance *ti, Scope *sc, Scope *paramscope, Objects *dedtypes, FuncDeclaration *fd);
+
+    MATCH matchWithInstance(Scope *sc, TemplateInstance *ti, Objects *atypes, Expressions *fargs, int flag);
+    MATCH leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs);
+
+    MATCH deduceFunctionTemplateMatch(TemplateInstance *ti, Scope *sc, FuncDeclaration *&fd, Type *tthis, Expressions *fargs);
+    RootObject *declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o);
+    FuncDeclaration *doHeaderInstantiation(TemplateInstance *ti, Scope *sc, FuncDeclaration *fd, Type *tthis, Expressions *fargs);
+    TemplateInstance *findExistingInstance(TemplateInstance *tithis, Expressions *fargs);
+    TemplateInstance *addInstance(TemplateInstance *ti);
+    void removeInstance(TemplateInstance *handle);
+
+    TemplateDeclaration *isTemplateDeclaration() { return this; }
+
+    TemplateTupleParameter *isVariadic();
+    bool isOverloadable();
+
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/* For type-parameter:
+ *  template Foo(ident)             // specType is set to NULL
+ *  template Foo(ident : specType)
+ * For value-parameter:
+ *  template Foo(valType ident)     // specValue is set to NULL
+ *  template Foo(valType ident : specValue)
+ * For alias-parameter:
+ *  template Foo(alias ident)
+ * For this-parameter:
+ *  template Foo(this ident)
+ */
+class TemplateParameter
+{
+public:
+    Loc loc;
+    Identifier *ident;
+
+    /* True if this is a part of precedent parameter specialization pattern.
+     *
+     *  template A(T : X!TL, alias X, TL...) {}
+     *  // X and TL are dependent template parameter
+     *
+     * A dependent template parameter should return MATCHexact in matchArg()
+     * to respect the match level of the corresponding precedent parameter.
+     */
+    bool dependent;
+
+    TemplateParameter(Loc loc, Identifier *ident);
+
+    virtual TemplateTypeParameter  *isTemplateTypeParameter();
+    virtual TemplateValueParameter *isTemplateValueParameter();
+    virtual TemplateAliasParameter *isTemplateAliasParameter();
+    virtual TemplateThisParameter *isTemplateThisParameter();
+    virtual TemplateTupleParameter *isTemplateTupleParameter();
+
+    virtual TemplateParameter *syntaxCopy() = 0;
+    virtual bool declareParameter(Scope *sc) = 0;
+    virtual bool semantic(Scope *sc, TemplateParameters *parameters) = 0;
+    virtual void print(RootObject *oarg, RootObject *oded) = 0;
+    virtual RootObject *specialization() = 0;
+    virtual RootObject *defaultArg(Loc instLoc, Scope *sc) = 0;
+    virtual bool hasDefaultArg() = 0;
+
+    /* Match actual argument against parameter.
+     */
+    virtual MATCH matchArg(Loc instLoc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+    virtual MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 0;
+
+    /* Create dummy argument based on parameter.
+     */
+    virtual void *dummyArg() = 0;
+    virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Syntax:
+ *  ident : specType = defaultType
+ */
+class TemplateTypeParameter : public TemplateParameter
+{
+public:
+    Type *specType;     // type parameter: if !=NULL, this is the type specialization
+    Type *defaultType;
+
+    static Type *tdummy;
+
+    TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType);
+
+    TemplateTypeParameter *isTemplateTypeParameter();
+    TemplateParameter *syntaxCopy();
+    bool declareParameter(Scope *sc);
+    bool semantic(Scope *sc, TemplateParameters *parameters);
+    void print(RootObject *oarg, RootObject *oded);
+    RootObject *specialization();
+    RootObject *defaultArg(Loc instLoc, Scope *sc);
+    bool hasDefaultArg();
+    MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+    void *dummyArg();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Syntax:
+ *  this ident : specType = defaultType
+ */
+class TemplateThisParameter : public TemplateTypeParameter
+{
+public:
+    TemplateThisParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType);
+
+    TemplateThisParameter *isTemplateThisParameter();
+    TemplateParameter *syntaxCopy();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Syntax:
+ *  valType ident : specValue = defaultValue
+ */
+class TemplateValueParameter : public TemplateParameter
+{
+public:
+    Type *valType;
+    Expression *specValue;
+    Expression *defaultValue;
+
+    static AA *edummies;
+
+    TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue);
+
+    TemplateValueParameter *isTemplateValueParameter();
+    TemplateParameter *syntaxCopy();
+    bool declareParameter(Scope *sc);
+    bool semantic(Scope *sc, TemplateParameters *parameters);
+    void print(RootObject *oarg, RootObject *oded);
+    RootObject *specialization();
+    RootObject *defaultArg(Loc instLoc, Scope *sc);
+    bool hasDefaultArg();
+    MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+    void *dummyArg();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Syntax:
+ *  specType ident : specAlias = defaultAlias
+ */
+class TemplateAliasParameter : public TemplateParameter
+{
+public:
+    Type *specType;
+    RootObject *specAlias;
+    RootObject *defaultAlias;
+
+    static Dsymbol *sdummy;
+
+    TemplateAliasParameter(Loc loc, Identifier *ident, Type *specType, RootObject *specAlias, RootObject *defaultAlias);
+
+    TemplateAliasParameter *isTemplateAliasParameter();
+    TemplateParameter *syntaxCopy();
+    bool declareParameter(Scope *sc);
+    bool semantic(Scope *sc, TemplateParameters *parameters);
+    void print(RootObject *oarg, RootObject *oded);
+    RootObject *specialization();
+    RootObject *defaultArg(Loc instLoc, Scope *sc);
+    bool hasDefaultArg();
+    MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+    void *dummyArg();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Syntax:
+ *  ident ...
+ */
+class TemplateTupleParameter : public TemplateParameter
+{
+public:
+    TemplateTupleParameter(Loc loc, Identifier *ident);
+
+    TemplateTupleParameter *isTemplateTupleParameter();
+    TemplateParameter *syntaxCopy();
+    bool declareParameter(Scope *sc);
+    bool semantic(Scope *sc, TemplateParameters *parameters);
+    void print(RootObject *oarg, RootObject *oded);
+    RootObject *specialization();
+    RootObject *defaultArg(Loc instLoc, Scope *sc);
+    bool hasDefaultArg();
+    MATCH matchArg(Loc loc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+    MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+    void *dummyArg();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Given:
+ *  foo!(args) =>
+ *      name = foo
+ *      tiargs = args
+ */
+class TemplateInstance : public ScopeDsymbol
+{
+public:
+    Identifier *name;
+
+    // Array of Types/Expressions of template
+    // instance arguments [int*, char, 10*10]
+    Objects *tiargs;
+
+    // Array of Types/Expressions corresponding
+    // to TemplateDeclaration.parameters
+    // [int, char, 100]
+    Objects tdtypes;
+
+    Dsymbol *tempdecl;                  // referenced by foo.bar.abc
+    Dsymbol *enclosing;                 // if referencing local symbols, this is the context
+    Dsymbol *aliasdecl;                 // !=NULL if instance is an alias for its sole member
+    TemplateInstance *inst;             // refer to existing instance
+    ScopeDsymbol *argsym;               // argument symbol table
+    int inuse;                          // for recursive expansion detection
+    int nest;                           // for recursive pretty printing detection
+    bool semantictiargsdone;            // has semanticTiargs() been done?
+    bool havetempdecl;                  // if used second constructor
+    bool gagged;                        // if the instantiation is done with error gagging
+    hash_t hash;                        // cached result of toHash()
+    Expressions *fargs;                 // for function template, these are the function arguments
+
+    TemplateInstances* deferred;
+
+    Module *memberOf;                   // if !null, then this TemplateInstance appears in memberOf.members[]
+
+    // Used to determine the instance needs code generation.
+    // Note that these are inaccurate until semantic analysis phase completed.
+    TemplateInstance *tinst;            // enclosing template instance
+    TemplateInstance *tnext;            // non-first instantiated instances
+    Module *minst;                      // the top module that instantiated this instance
+
+    TemplateInstance(Loc loc, Identifier *temp_id);
+    TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs);
+    static Objects *arraySyntaxCopy(Objects *objs);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc, Expressions *fargs);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    Dsymbol *toAlias();                 // resolve real symbol
+    const char *kind();
+    bool oneMember(Dsymbol **ps, Identifier *ident);
+    const char *toChars();
+    const char* toPrettyCharsHelper();
+    void printInstantiationTrace();
+    Identifier *getIdent();
+    int compare(RootObject *o);
+    hash_t toHash();
+
+    bool needsCodegen();
+
+    // Internal
+    bool findTempDecl(Scope *sc, WithScopeSymbol **pwithsym);
+    bool updateTempDecl(Scope *sc, Dsymbol *s);
+    static bool semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags);
+    bool semanticTiargs(Scope *sc);
+    bool findBestMatch(Scope *sc, Expressions *fargs);
+    bool needsTypeInference(Scope *sc, int flag = 0);
+    bool hasNestedArgs(Objects *tiargs, bool isstatic);
+    Dsymbols *appendToModuleMember();
+    void declareParameters(Scope *sc);
+    Identifier *genIdent(Objects *args);
+    void expandMembers(Scope *sc);
+    void tryExpandMembers(Scope *sc);
+    void trySemantic3(Scope *sc2);
+
+    TemplateInstance *isTemplateInstance() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class TemplateMixin : public TemplateInstance
+{
+public:
+    TypeQualified *tqual;
+
+    TemplateMixin(Loc loc, Identifier *ident, TypeQualified *tqual, Objects *tiargs);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    const char *kind();
+    bool oneMember(Dsymbol **ps, Identifier *ident);
+    int apply(Dsymbol_apply_ft_t fp, void *param);
+    bool hasPointers();
+    void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+    const char *toChars();
+
+    bool findTempDecl(Scope *sc);
+
+    TemplateMixin *isTemplateMixin() { return this; }
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+Expression *isExpression(RootObject *o);
+Dsymbol *isDsymbol(RootObject *o);
+Type *isType(RootObject *o);
+Tuple *isTuple(RootObject *o);
+Parameter *isParameter(RootObject *o);
+bool arrayObjectIsError(Objects *args);
+bool isError(RootObject *o);
+Type *getType(RootObject *o);
+Dsymbol *getDsymbol(RootObject *o);
+
+RootObject *objectSyntaxCopy(RootObject *o);
+
+#endif /* DMD_TEMPLATE_H */
diff --git a/gcc/d/dfrontend/tokens.c b/gcc/d/dfrontend/tokens.c
new file mode 100644
index 00000000000..6f068ef1027
--- /dev/null
+++ b/gcc/d/dfrontend/tokens.c
@@ -0,0 +1,484 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/lexer.c
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "tokens.h"
+#include "rmem.h"
+#include "outbuffer.h"
+#include "id.h"
+#include "identifier.h"
+#include "utf.h"
+
+/************************* Token **********************************************/
+
+Token *Token::freelist = NULL;
+
+const char *Token::tochars[TOKMAX];
+
+Token *Token::alloc()
+{
+    if (Token::freelist)
+    {
+        Token *t = freelist;
+        freelist = t->next;
+        t->next = NULL;
+        return t;
+    }
+
+    return new Token();
+}
+
+void Token::free()
+{
+    next = freelist;
+    freelist = this;
+}
+
+#ifdef DEBUG
+void Token::print()
+{
+    fprintf(stderr, "%s\n", toChars());
+}
+#endif
+
+const char *Token::toChars() const
+{
+    static char buffer[3 + 3 * sizeof(floatvalue) + 1];
+
+    const char *p = &buffer[0];
+    switch (value)
+    {
+        case TOKint32v:
+            sprintf(&buffer[0],"%d",(d_int32)int64value);
+            break;
+
+        case TOKuns32v:
+        case TOKcharv:
+        case TOKwcharv:
+        case TOKdcharv:
+            sprintf(&buffer[0],"%uU",(d_uns32)uns64value);
+            break;
+
+        case TOKint64v:
+            sprintf(&buffer[0],"%lldL",(longlong)int64value);
+            break;
+
+        case TOKuns64v:
+            sprintf(&buffer[0],"%lluUL",(ulonglong)uns64value);
+            break;
+
+        case TOKfloat32v:
+            CTFloat::sprint(&buffer[0], 'g', floatvalue);
+            strcat(&buffer[0], "f");
+            break;
+
+        case TOKfloat64v:
+            CTFloat::sprint(&buffer[0], 'g', floatvalue);
+            break;
+
+        case TOKfloat80v:
+            CTFloat::sprint(&buffer[0], 'g', floatvalue);
+            strcat(&buffer[0], "L");
+            break;
+
+        case TOKimaginary32v:
+            CTFloat::sprint(&buffer[0], 'g', floatvalue);
+            strcat(&buffer[0], "fi");
+            break;
+
+        case TOKimaginary64v:
+            CTFloat::sprint(&buffer[0], 'g', floatvalue);
+            strcat(&buffer[0], "i");
+            break;
+
+        case TOKimaginary80v:
+            CTFloat::sprint(&buffer[0], 'g', floatvalue);
+            strcat(&buffer[0], "Li");
+            break;
+
+        case TOKstring:
+        {
+            OutBuffer buf;
+            buf.writeByte('"');
+            for (size_t i = 0; i < len; )
+            {
+                unsigned c;
+                utf_decodeChar((utf8_t *)ustring, len, &i, &c);
+                switch (c)
+                {
+                    case 0:
+                        break;
+
+                    case '"':
+                    case '\\':
+                        buf.writeByte('\\');
+                    default:
+                        if (c <= 0x7F)
+                        {
+                            if (isprint(c))
+                                buf.writeByte(c);
+                            else
+                                buf.printf("\\x%02x", c);
+                        }
+                        else if (c <= 0xFFFF)
+                            buf.printf("\\u%04x", c);
+                        else
+                            buf.printf("\\U%08x", c);
+                        continue;
+                }
+                break;
+            }
+            buf.writeByte('"');
+            if (postfix)
+                buf.writeByte(postfix);
+            p = buf.extractString();
+        }
+            break;
+
+        case TOKxstring:
+        {
+            OutBuffer buf;
+            buf.writeByte('x');
+            buf.writeByte('"');
+            for (size_t i = 0; i < len; i++)
+            {
+                if (i)
+                    buf.writeByte(' ');
+                buf.printf("%02x", ustring[i]);
+            }
+            buf.writeByte('"');
+            if (postfix)
+                buf.writeByte(postfix);
+            buf.writeByte(0);
+            p = (char *)buf.extractData();
+            break;
+        }
+
+        case TOKidentifier:
+        case TOKenum:
+        case TOKstruct:
+        case TOKimport:
+        case TOKwchar: case TOKdchar:
+        case TOKbool: case TOKchar:
+        case TOKint8: case TOKuns8:
+        case TOKint16: case TOKuns16:
+        case TOKint32: case TOKuns32:
+        case TOKint64: case TOKuns64:
+        case TOKint128: case TOKuns128:
+        case TOKfloat32: case TOKfloat64: case TOKfloat80:
+        case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+        case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+        case TOKvoid:
+            p = ident->toChars();
+            break;
+
+        default:
+            p = toChars(value);
+            break;
+    }
+    return p;
+}
+
+const char *Token::toChars(TOK value)
+{
+    static char buffer[3 + 3 * sizeof(value) + 1];
+
+    const char *p = tochars[value];
+    if (!p)
+    {
+        sprintf(&buffer[0],"TOK%d",value);
+        p = &buffer[0];
+    }
+    return p;
+}
+
+/****************************************
+ */
+
+struct Keyword
+{
+    const char *name;
+    TOK value;
+};
+
+static size_t nkeywords;
+static Keyword keywords[] =
+{
+    {   "this",         TOKthis         },
+    {   "super",        TOKsuper        },
+    {   "assert",       TOKassert       },
+    {   "null",         TOKnull         },
+    {   "true",         TOKtrue         },
+    {   "false",        TOKfalse        },
+    {   "cast",         TOKcast         },
+    {   "new",          TOKnew          },
+    {   "delete",       TOKdelete       },
+    {   "throw",        TOKthrow        },
+    {   "module",       TOKmodule       },
+    {   "pragma",       TOKpragma       },
+    {   "typeof",       TOKtypeof       },
+    {   "typeid",       TOKtypeid       },
+
+    {   "template",     TOKtemplate     },
+
+    {   "void",         TOKvoid         },
+    {   "byte",         TOKint8         },
+    {   "ubyte",        TOKuns8         },
+    {   "short",        TOKint16        },
+    {   "ushort",       TOKuns16        },
+    {   "int",          TOKint32        },
+    {   "uint",         TOKuns32        },
+    {   "long",         TOKint64        },
+    {   "ulong",        TOKuns64        },
+    {   "cent",         TOKint128,      },
+    {   "ucent",        TOKuns128,      },
+    {   "float",        TOKfloat32      },
+    {   "double",       TOKfloat64      },
+    {   "real",         TOKfloat80      },
+
+    {   "bool",         TOKbool         },
+    {   "char",         TOKchar         },
+    {   "wchar",        TOKwchar        },
+    {   "dchar",        TOKdchar        },
+
+    {   "ifloat",       TOKimaginary32  },
+    {   "idouble",      TOKimaginary64  },
+    {   "ireal",        TOKimaginary80  },
+
+    {   "cfloat",       TOKcomplex32    },
+    {   "cdouble",      TOKcomplex64    },
+    {   "creal",        TOKcomplex80    },
+
+    {   "delegate",     TOKdelegate     },
+    {   "function",     TOKfunction     },
+
+    {   "is",           TOKis           },
+    {   "if",           TOKif           },
+    {   "else",         TOKelse         },
+    {   "while",        TOKwhile        },
+    {   "for",          TOKfor          },
+    {   "do",           TOKdo           },
+    {   "switch",       TOKswitch       },
+    {   "case",         TOKcase         },
+    {   "default",      TOKdefault      },
+    {   "break",        TOKbreak        },
+    {   "continue",     TOKcontinue     },
+    {   "synchronized", TOKsynchronized },
+    {   "return",       TOKreturn       },
+    {   "goto",         TOKgoto         },
+    {   "try",          TOKtry          },
+    {   "catch",        TOKcatch        },
+    {   "finally",      TOKfinally      },
+    {   "with",         TOKwith         },
+    {   "asm",          TOKasm          },
+    {   "foreach",      TOKforeach      },
+    {   "foreach_reverse",      TOKforeach_reverse      },
+    {   "scope",        TOKscope        },
+
+    {   "struct",       TOKstruct       },
+    {   "class",        TOKclass        },
+    {   "interface",    TOKinterface    },
+    {   "union",        TOKunion        },
+    {   "enum",         TOKenum         },
+    {   "import",       TOKimport       },
+    {   "mixin",        TOKmixin        },
+    {   "static",       TOKstatic       },
+    {   "final",        TOKfinal        },
+    {   "const",        TOKconst        },
+    {   "alias",        TOKalias        },
+    {   "override",     TOKoverride     },
+    {   "abstract",     TOKabstract     },
+    {   "debug",        TOKdebug        },
+    {   "deprecated",   TOKdeprecated   },
+    {   "in",           TOKin           },
+    {   "out",          TOKout          },
+    {   "inout",        TOKinout        },
+    {   "lazy",         TOKlazy         },
+    {   "auto",         TOKauto         },
+
+    {   "align",        TOKalign        },
+    {   "extern",       TOKextern       },
+    {   "private",      TOKprivate      },
+    {   "package",      TOKpackage      },
+    {   "protected",    TOKprotected    },
+    {   "public",       TOKpublic       },
+    {   "export",       TOKexport       },
+
+    {   "body",         TOKbody         },
+    {   "invariant",    TOKinvariant    },
+    {   "unittest",     TOKunittest     },
+    {   "version",      TOKversion      },
+
+    {   "__argTypes",   TOKargTypes     },
+    {   "__parameters", TOKparameters   },
+    {   "ref",          TOKref          },
+    {   "macro",        TOKmacro        },
+
+    {   "pure",         TOKpure         },
+    {   "nothrow",      TOKnothrow      },
+    {   "__gshared",    TOKgshared      },
+    {   "__traits",     TOKtraits       },
+    {   "__vector",     TOKvector       },
+    {   "__overloadset", TOKoverloadset },
+    {   "__FILE__",     TOKfile         },
+    {   "__FILE_FULL_PATH__", TOKfilefullpath  },
+    {   "__LINE__",     TOKline         },
+    {   "__MODULE__",   TOKmodulestring },
+    {   "__FUNCTION__", TOKfuncstring   },
+    {   "__PRETTY_FUNCTION__", TOKprettyfunc   },
+    {   "shared",       TOKshared       },
+    {   "immutable",    TOKimmutable    },
+    {   NULL,           TOKreserved     }
+};
+
+int Token::isKeyword()
+{
+    for (size_t u = 0; u < nkeywords; u++)
+    {
+        if (keywords[u].value == value)
+            return 1;
+    }
+    return 0;
+}
+
+struct TokenInitializer
+{
+    TokenInitializer();
+};
+
+static TokenInitializer tokeninitializer;
+
+TokenInitializer::TokenInitializer()
+{
+    Identifier::initTable();
+    for (nkeywords = 0; keywords[nkeywords].name; nkeywords++)
+    {
+        //printf("keyword[%d] = '%s'\n",u, keywords[u].name);
+        const char *s = keywords[nkeywords].name;
+        size_t len = strlen(s);
+        TOK v = keywords[nkeywords].value;
+        Identifier *id = Identifier::idPool(s, len, v);
+
+        //printf("tochars[%d] = '%s'\n",v, s);
+        Token::tochars[v] = s;
+    }
+
+    Token::tochars[TOKeof]              = "EOF";
+    Token::tochars[TOKlcurly]           = "{";
+    Token::tochars[TOKrcurly]           = "}";
+    Token::tochars[TOKlparen]           = "(";
+    Token::tochars[TOKrparen]           = ")";
+    Token::tochars[TOKlbracket]         = "[";
+    Token::tochars[TOKrbracket]         = "]";
+    Token::tochars[TOKsemicolon]        = ";";
+    Token::tochars[TOKcolon]            = ":";
+    Token::tochars[TOKcomma]            = ",";
+    Token::tochars[TOKdot]              = ".";
+    Token::tochars[TOKxor]              = "^";
+    Token::tochars[TOKxorass]           = "^=";
+    Token::tochars[TOKassign]           = "=";
+    Token::tochars[TOKconstruct]        = "=";
+    Token::tochars[TOKblit]             = "=";
+    Token::tochars[TOKlt]               = "<";
+    Token::tochars[TOKgt]               = ">";
+    Token::tochars[TOKle]               = "<=";
+    Token::tochars[TOKge]               = ">=";
+    Token::tochars[TOKequal]            = "==";
+    Token::tochars[TOKnotequal]         = "!=";
+    Token::tochars[TOKnotidentity]      = "!is";
+
+    Token::tochars[TOKunord]            = "!<>=";
+    Token::tochars[TOKue]               = "!<>";
+    Token::tochars[TOKlg]               = "<>";
+    Token::tochars[TOKleg]              = "<>=";
+    Token::tochars[TOKule]              = "!>";
+    Token::tochars[TOKul]               = "!>=";
+    Token::tochars[TOKuge]              = "!<";
+    Token::tochars[TOKug]               = "!<=";
+
+    Token::tochars[TOKnot]              = "!";
+    Token::tochars[TOKshl]              = "<<";
+    Token::tochars[TOKshr]              = ">>";
+    Token::tochars[TOKushr]             = ">>>";
+    Token::tochars[TOKadd]              = "+";
+    Token::tochars[TOKmin]              = "-";
+    Token::tochars[TOKmul]              = "*";
+    Token::tochars[TOKdiv]              = "/";
+    Token::tochars[TOKmod]              = "%";
+    Token::tochars[TOKslice]            = "..";
+    Token::tochars[TOKdotdotdot]        = "...";
+    Token::tochars[TOKand]              = "&";
+    Token::tochars[TOKandand]           = "&&";
+    Token::tochars[TOKor]               = "|";
+    Token::tochars[TOKoror]             = "||";
+    Token::tochars[TOKarray]            = "[]";
+    Token::tochars[TOKindex]            = "[i]";
+    Token::tochars[TOKaddress]          = "&";
+    Token::tochars[TOKstar]             = "*";
+    Token::tochars[TOKtilde]            = "~";
+    Token::tochars[TOKdollar]           = "$";
+    Token::tochars[TOKcast]             = "cast";
+    Token::tochars[TOKplusplus]         = "++";
+    Token::tochars[TOKminusminus]       = "--";
+    Token::tochars[TOKpreplusplus]      = "++";
+    Token::tochars[TOKpreminusminus]    = "--";
+    Token::tochars[TOKtype]             = "type";
+    Token::tochars[TOKquestion]         = "?";
+    Token::tochars[TOKneg]              = "-";
+    Token::tochars[TOKuadd]             = "+";
+    Token::tochars[TOKvar]              = "var";
+    Token::tochars[TOKaddass]           = "+=";
+    Token::tochars[TOKminass]           = "-=";
+    Token::tochars[TOKmulass]           = "*=";
+    Token::tochars[TOKdivass]           = "/=";
+    Token::tochars[TOKmodass]           = "%=";
+    Token::tochars[TOKshlass]           = "<<=";
+    Token::tochars[TOKshrass]           = ">>=";
+    Token::tochars[TOKushrass]          = ">>>=";
+    Token::tochars[TOKandass]           = "&=";
+    Token::tochars[TOKorass]            = "|=";
+    Token::tochars[TOKcatass]           = "~=";
+    Token::tochars[TOKcat]              = "~";
+    Token::tochars[TOKcall]             = "call";
+    Token::tochars[TOKidentity]         = "is";
+    Token::tochars[TOKnotidentity]      = "!is";
+
+    Token::tochars[TOKorass]            = "|=";
+    Token::tochars[TOKidentifier]       = "identifier";
+    Token::tochars[TOKat]               = "@";
+    Token::tochars[TOKpow]              = "^^";
+    Token::tochars[TOKpowass]           = "^^=";
+    Token::tochars[TOKgoesto]           = "=>";
+    Token::tochars[TOKpound]            = "#";
+
+     // For debugging
+    Token::tochars[TOKerror]            = "error";
+    Token::tochars[TOKdotid]            = "dotid";
+    Token::tochars[TOKdottd]            = "dottd";
+    Token::tochars[TOKdotti]            = "dotti";
+    Token::tochars[TOKdotvar]           = "dotvar";
+    Token::tochars[TOKdottype]          = "dottype";
+    Token::tochars[TOKsymoff]           = "symoff";
+    Token::tochars[TOKarraylength]      = "arraylength";
+    Token::tochars[TOKarrayliteral]     = "arrayliteral";
+    Token::tochars[TOKassocarrayliteral] = "assocarrayliteral";
+    Token::tochars[TOKstructliteral]    = "structliteral";
+    Token::tochars[TOKstring]           = "string";
+    Token::tochars[TOKdsymbol]          = "symbol";
+    Token::tochars[TOKtuple]            = "tuple";
+    Token::tochars[TOKdeclaration]      = "declaration";
+    Token::tochars[TOKon_scope_exit]    = "scope(exit)";
+    Token::tochars[TOKon_scope_success] = "scope(success)";
+    Token::tochars[TOKon_scope_failure] = "scope(failure)";
+    Token::tochars[TOKdelegateptr]      = "delegateptr";
+}
diff --git a/gcc/d/dfrontend/tokens.h b/gcc/d/dfrontend/tokens.h
new file mode 100644
index 00000000000..0475c5ab5e3
--- /dev/null
+++ b/gcc/d/dfrontend/tokens.h
@@ -0,0 +1,234 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/tokens.h
+ */
+
+#ifndef DMD_TOKENS_H
+#define DMD_TOKENS_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "port.h"
+#include "mars.h"
+
+class Identifier;
+
+/* Tokens:
+        (       )
+        [       ]
+        {       }
+        <       >       <=      >=      ==      !=      ===     !==
+        <<      >>      <<=     >>=     >>>     >>>=
+        +       -       +=      -=
+        *       /       %       *=      /=      %=
+        &       |       ^       &=      |=      ^=
+        =       !       ~       @
+        ^^      ^^=
+        ++      --
+        .       ->      :       ,       =>
+        ?       &&      ||
+ */
+
+enum TOK
+{
+        TOKreserved,
+
+        // Other
+        TOKlparen,      TOKrparen,
+        TOKlbracket,    TOKrbracket,
+        TOKlcurly,      TOKrcurly,
+        TOKcolon,       TOKneg,
+        TOKsemicolon,   TOKdotdotdot,
+        TOKeof,         TOKcast,
+        TOKnull,        TOKassert,
+        TOKtrue,        TOKfalse,
+        TOKarray,       TOKcall,
+        TOKaddress,
+        TOKtype,        TOKthrow,
+        TOKnew,         TOKdelete,
+        TOKstar,        TOKsymoff,
+        TOKvar,         TOKdotvar,
+        TOKdotid,       TOKdotti,
+        TOKdottype,     TOKslice,
+        TOKarraylength, TOKversion,
+        TOKmodule,      TOKdollar,
+        TOKtemplate,    TOKdottd,
+        TOKdeclaration, TOKtypeof,
+        TOKpragma,      TOKdsymbol,
+        TOKtypeid,      TOKuadd,
+        TOKremove,
+        TOKnewanonclass, TOKcomment,
+        TOKarrayliteral, TOKassocarrayliteral,
+        TOKstructliteral,
+        TOKclassreference,
+        TOKthrownexception,
+        TOKdelegateptr,
+        TOKdelegatefuncptr,
+
+// 54
+        // Operators
+        TOKlt,          TOKgt,
+        TOKle,          TOKge,
+        TOKequal,       TOKnotequal,
+        TOKidentity,    TOKnotidentity,
+        TOKindex,       TOKis,
+
+// 64
+        // NCEG floating point compares
+        // !<>=     <>    <>=    !>     !>=   !<     !<=   !<>
+        TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue,
+
+// 72
+        TOKshl,         TOKshr,
+        TOKshlass,      TOKshrass,
+        TOKushr,        TOKushrass,
+        TOKcat,         TOKcatass,      // ~ ~=
+        TOKadd,         TOKmin,         TOKaddass,      TOKminass,
+        TOKmul,         TOKdiv,         TOKmod,
+        TOKmulass,      TOKdivass,      TOKmodass,
+        TOKand,         TOKor,          TOKxor,
+        TOKandass,      TOKorass,       TOKxorass,
+        TOKassign,      TOKnot,         TOKtilde,
+        TOKplusplus,    TOKminusminus,  TOKconstruct,   TOKblit,
+        TOKdot,         TOKarrow,       TOKcomma,
+        TOKquestion,    TOKandand,      TOKoror,
+        TOKpreplusplus, TOKpreminusminus,
+
+// 111
+        // Numeric literals
+        TOKint32v, TOKuns32v,
+        TOKint64v, TOKuns64v,
+        TOKint128v, TOKuns128v,
+        TOKfloat32v, TOKfloat64v, TOKfloat80v,
+        TOKimaginary32v, TOKimaginary64v, TOKimaginary80v,
+
+        // Char constants
+        TOKcharv, TOKwcharv, TOKdcharv,
+
+        // Leaf operators
+        TOKidentifier,  TOKstring, TOKxstring,
+        TOKthis,        TOKsuper,
+        TOKhalt,        TOKtuple,
+        TOKerror,
+
+        // Basic types
+        TOKvoid,
+        TOKint8, TOKuns8,
+        TOKint16, TOKuns16,
+        TOKint32, TOKuns32,
+        TOKint64, TOKuns64,
+        TOKint128, TOKuns128,
+        TOKfloat32, TOKfloat64, TOKfloat80,
+        TOKimaginary32, TOKimaginary64, TOKimaginary80,
+        TOKcomplex32, TOKcomplex64, TOKcomplex80,
+        TOKchar, TOKwchar, TOKdchar, TOKbool,
+
+// 158
+        // Aggregates
+        TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport,
+        TOKalias, TOKoverride, TOKdelegate, TOKfunction,
+        TOKmixin,
+
+        TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport,
+        TOKstatic, TOKfinal, TOKconst, TOKabstract,
+        TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy,
+        TOKauto, TOKpackage, TOKmanifest, TOKimmutable,
+
+        // Statements
+        TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch,
+        TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith,
+        TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally,
+        TOKasm, TOKforeach, TOKforeach_reverse,
+        TOKscope,
+        TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success,
+
+        // Contracts
+        TOKbody, TOKinvariant,
+
+        // Testing
+        TOKunittest,
+
+        // Added after 1.0
+        TOKargTypes,
+        TOKref,
+        TOKmacro,
+
+        TOKparameters,
+        TOKtraits,
+        TOKoverloadset,
+        TOKpure,
+        TOKnothrow,
+        TOKgshared,
+        TOKline,
+        TOKfile,
+        TOKfilefullpath,
+        TOKmodulestring,
+        TOKfuncstring,
+        TOKprettyfunc,
+        TOKshared,
+        TOKat,
+        TOKpow,
+        TOKpowass,
+        TOKgoesto,
+        TOKvector,
+        TOKpound,
+
+        TOKinterval,
+        TOKvoidexp,
+        TOKcantexp,
+
+        TOKMAX
+};
+
+#define TOKwild TOKinout
+
+struct Token
+{
+    Token *next;
+    Loc loc;
+    const utf8_t *ptr;         // pointer to first character of this token within buffer
+    TOK value;
+    const utf8_t *blockComment; // doc comment string prior to this token
+    const utf8_t *lineComment;  // doc comment for previous token
+    union
+    {
+        // Integers
+        d_int64 int64value;
+        d_uns64 uns64value;
+
+        // Floats
+        real_t floatvalue;
+
+        struct
+        {   utf8_t *ustring;     // UTF8 string
+            unsigned len;
+            unsigned char postfix;      // 'c', 'w', 'd'
+        };
+
+        Identifier *ident;
+    };
+
+    static const char *tochars[TOKMAX];
+
+    static Token *freelist;
+    static Token *alloc();
+    void free();
+
+    Token() : next(NULL) {}
+    int isKeyword();
+#ifdef DEBUG
+    void print();
+#endif
+    const char *toChars() const;
+    static const char *toChars(TOK);
+};
+
+#endif /* DMD_TOKENS_H */
diff --git a/gcc/d/dfrontend/traits.c b/gcc/d/dfrontend/traits.c
new file mode 100644
index 00000000000..fb7949322cb
--- /dev/null
+++ b/gcc/d/dfrontend/traits.c
@@ -0,0 +1,1476 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/traits.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <math.h>
+
+#include "rmem.h"
+#include "aav.h"
+#include "checkedint.h"
+
+#include "mtype.h"
+#include "init.h"
+#include "expression.h"
+#include "template.h"
+#include "utf.h"
+#include "enum.h"
+#include "scope.h"
+#include "hdrgen.h"
+#include "statement.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "import.h"
+#include "id.h"
+#include "dsymbol.h"
+#include "module.h"
+#include "attrib.h"
+#include "parse.h"
+#include "speller.h"
+
+#define LOGSEMANTIC     0
+
+typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s);
+int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL);
+void freeFieldinit(Scope *sc);
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+Expression *trySemantic(Expression *e, Scope *sc);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *typeToExpression(Type *t);
+
+
+/************************************************
+ * Delegate to be passed to overloadApply() that looks
+ * for functions matching a trait.
+ */
+
+struct Ptrait
+{
+    Expression *e1;
+    Expressions *exps;          // collected results
+    Identifier *ident;          // which trait we're looking for
+};
+
+static int fptraits(void *param, Dsymbol *s)
+{
+    FuncDeclaration *f = s->isFuncDeclaration();
+    if (!f)
+        return 0;
+
+    Ptrait *p = (Ptrait *)param;
+    if (p->ident == Id::getVirtualFunctions && !f->isVirtual())
+        return 0;
+
+    if (p->ident == Id::getVirtualMethods && !f->isVirtualMethod())
+        return 0;
+
+    Expression *e;
+    FuncAliasDeclaration* ad = new FuncAliasDeclaration(f->ident, f, false);
+    ad->protection = f->protection;
+    if (p->e1)
+        e = new DotVarExp(Loc(), p->e1, ad, false);
+    else
+        e = new DsymbolExp(Loc(), ad, false);
+    p->exps->push(e);
+    return 0;
+}
+
+/**
+ * Collects all unit test functions from the given array of symbols.
+ *
+ * This is a helper function used by the implementation of __traits(getUnitTests).
+ *
+ * Input:
+ *      symbols             array of symbols to collect the functions from
+ *      uniqueUnitTests     an associative array (should actually be a set) to
+ *                          keep track of already collected functions. We're
+ *                          using an AA here to avoid doing a linear search of unitTests
+ *
+ * Output:
+ *      unitTests           array of DsymbolExp's of the collected unit test functions
+ *      uniqueUnitTests     updated with symbols from unitTests[ ]
+ */
+static void collectUnitTests(Dsymbols *symbols, AA *uniqueUnitTests, Expressions *unitTests)
+{
+    if (!symbols)
+        return;
+    for (size_t i = 0; i < symbols->dim; i++)
+    {
+        Dsymbol *symbol = (*symbols)[i];
+        UnitTestDeclaration *unitTest = symbol->isUnitTestDeclaration();
+        if (unitTest)
+        {
+            if (!dmd_aaGetRvalue(uniqueUnitTests, (void *)unitTest))
+            {
+                FuncAliasDeclaration* ad = new FuncAliasDeclaration(unitTest->ident, unitTest, false);
+                ad->protection = unitTest->protection;
+                Expression* e = new DsymbolExp(Loc(), ad, false);
+                unitTests->push(e);
+                bool* value = (bool*) dmd_aaGet(&uniqueUnitTests, (void *)unitTest);
+                *value = true;
+            }
+        }
+        else
+        {
+            AttribDeclaration *attrDecl = symbol->isAttribDeclaration();
+
+            if (attrDecl)
+            {
+                Dsymbols *decl = attrDecl->include(NULL, NULL);
+                collectUnitTests(decl, uniqueUnitTests, unitTests);
+            }
+        }
+    }
+}
+
+/************************ TraitsExp ************************************/
+
+static Expression *True(TraitsExp *e)  { return new IntegerExp(e->loc, true, Type::tbool); }
+static Expression *False(TraitsExp *e) { return new IntegerExp(e->loc, false, Type::tbool); }
+
+bool isTypeArithmetic(Type *t)       { return t->isintegral() || t->isfloating(); }
+bool isTypeFloating(Type *t)         { return t->isfloating(); }
+bool isTypeIntegral(Type *t)         { return t->isintegral(); }
+bool isTypeScalar(Type *t)           { return t->isscalar(); }
+bool isTypeUnsigned(Type *t)         { return t->isunsigned(); }
+bool isTypeAssociativeArray(Type *t) { return t->toBasetype()->ty == Taarray; }
+bool isTypeStaticArray(Type *t)      { return t->toBasetype()->ty == Tsarray; }
+bool isTypeAbstractClass(Type *t)    { return t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract(); }
+bool isTypeFinalClass(Type *t)       { return t->toBasetype()->ty == Tclass && (((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) != 0; }
+
+Expression *isTypeX(TraitsExp *e, bool (*fp)(Type *t))
+{
+    if (!e->args || !e->args->dim)
+        return False(e);
+    for (size_t i = 0; i < e->args->dim; i++)
+    {
+        Type *t = getType((*e->args)[i]);
+        if (!t || !fp(t))
+            return False(e);
+    }
+    return True(e);
+}
+
+bool isFuncAbstractFunction(FuncDeclaration *f) { return f->isAbstract(); }
+bool isFuncVirtualFunction(FuncDeclaration *f) { return f->isVirtual(); }
+bool isFuncVirtualMethod(FuncDeclaration *f) { return f->isVirtualMethod(); }
+bool isFuncFinalFunction(FuncDeclaration *f) { return f->isFinalFunc(); }
+bool isFuncStaticFunction(FuncDeclaration *f) { return !f->needThis() && !f->isNested(); }
+bool isFuncOverrideFunction(FuncDeclaration *f) { return f->isOverride(); }
+
+Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f))
+{
+    if (!e->args || !e->args->dim)
+        return False(e);
+    for (size_t i = 0; i < e->args->dim; i++)
+    {
+        Dsymbol *s = getDsymbol((*e->args)[i]);
+        if (!s)
+            return False(e);
+        FuncDeclaration *f = s->isFuncDeclaration();
+        if (!f || !fp(f))
+            return False(e);
+    }
+    return True(e);
+}
+
+bool isDeclRef(Declaration *d) { return d->isRef(); }
+bool isDeclOut(Declaration *d) { return d->isOut(); }
+bool isDeclLazy(Declaration *d) { return (d->storage_class & STClazy) != 0; }
+
+Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d))
+{
+    if (!e->args || !e->args->dim)
+        return False(e);
+    for (size_t i = 0; i < e->args->dim; i++)
+    {
+        Dsymbol *s = getDsymbol((*e->args)[i]);
+        if (!s)
+            return False(e);
+        Declaration *d = s->isDeclaration();
+        if (!d || !fp(d))
+            return False(e);
+    }
+    return True(e);
+}
+
+// callback for TypeFunction::attributesApply
+struct PushAttributes
+{
+    Expressions *mods;
+
+    static int fp(void *param, const char *str)
+    {
+        PushAttributes *p = (PushAttributes *)param;
+        p->mods->push(new StringExp(Loc(), (char *)str));
+        return 0;
+    }
+};
+
+StringTable traitsStringTable;
+
+struct TraitsInitializer
+{
+    TraitsInitializer();
+};
+
+static TraitsInitializer traitsinitializer;
+
+TraitsInitializer::TraitsInitializer()
+{
+    const char* traits[] = {
+        "isAbstractClass",
+        "isArithmetic",
+        "isAssociativeArray",
+        "isFinalClass",
+        "isPOD",
+        "isNested",
+        "isFloating",
+        "isIntegral",
+        "isScalar",
+        "isStaticArray",
+        "isUnsigned",
+        "isVirtualFunction",
+        "isVirtualMethod",
+        "isAbstractFunction",
+        "isFinalFunction",
+        "isOverrideFunction",
+        "isStaticFunction",
+        "isRef",
+        "isOut",
+        "isLazy",
+        "hasMember",
+        "identifier",
+        "getProtection",
+        "parent",
+        "getLinkage",
+        "getMember",
+        "getOverloads",
+        "getVirtualFunctions",
+        "getVirtualMethods",
+        "classInstanceSize",
+        "allMembers",
+        "derivedMembers",
+        "isSame",
+        "compiles",
+        "parameters",
+        "getAliasThis",
+        "getAttributes",
+        "getFunctionAttributes",
+        "getFunctionVariadicStyle",
+        "getParameterStorageClasses",
+        "getUnitTests",
+        "getVirtualIndex",
+        "getPointerBitmap",
+        NULL
+    };
+
+    traitsStringTable._init(40);
+
+    for (size_t idx = 0;; idx++)
+    {
+        const char *s = traits[idx];
+        if (!s) break;
+        StringValue *sv = traitsStringTable.insert(s, strlen(s), (void *)s);
+        assert(sv);
+    }
+}
+
+void *trait_search_fp(void *arg, const char *seed, int* cost)
+{
+    //printf("trait_search_fp('%s')\n", seed);
+    size_t len = strlen(seed);
+    if (!len)
+        return NULL;
+
+    *cost = 0;
+    StringValue *sv = traitsStringTable.lookup(seed, len);
+    return sv ? (void*)sv->ptrvalue : NULL;
+}
+
+static int fpisTemplate(void *param, Dsymbol *s)
+{
+    if (s->isTemplateDeclaration())
+        return 1;
+
+    return 0;
+}
+
+bool isTemplate(Dsymbol *s)
+{
+    if (!s->toAlias()->isOverloadable())
+        return false;
+
+    return overloadApply(s, NULL, &fpisTemplate) != 0;
+}
+
+Expression *isSymbolX(TraitsExp *e, bool (*fp)(Dsymbol *s))
+{
+    if (!e->args || !e->args->dim)
+        return False(e);
+    for (size_t i = 0; i < e->args->dim; i++)
+    {
+        Dsymbol *s = getDsymbol((*e->args)[i]);
+        if (!s || !fp(s))
+            return False(e);
+    }
+    return True(e);
+}
+
+/**
+ * get an array of size_t values that indicate possible pointer words in memory
+ *  if interpreted as the type given as argument
+ * the first array element is the size of the type for independent interpretation
+ *  of the array
+ * following elements bits represent one word (4/8 bytes depending on the target
+ *  architecture). If set the corresponding memory might contain a pointer/reference.
+ *
+ *  [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...]
+ */
+Expression *pointerBitmap(TraitsExp *e)
+{
+    if (!e->args || e->args->dim != 1)
+    {
+        error(e->loc, "a single type expected for trait pointerBitmap");
+        return new ErrorExp();
+    }
+    Type *t = getType((*e->args)[0]);
+    if (!t)
+    {
+        error(e->loc, "%s is not a type", (*e->args)[0]->toChars());
+        return new ErrorExp();
+    }
+    d_uns64 sz;
+    if (t->ty == Tclass && !((TypeClass*)t)->sym->isInterfaceDeclaration())
+        sz = ((TypeClass*)t)->sym->AggregateDeclaration::size(e->loc);
+    else
+        sz = t->size(e->loc);
+    if (sz == SIZE_INVALID)
+        return new ErrorExp();
+
+    const d_uns64 sz_size_t = Type::tsize_t->size(e->loc);
+    if (sz > UINT64_MAX - sz_size_t)
+    {
+        error(e->loc, "size overflow for type %s", t->toChars());
+        return new ErrorExp();
+    }
+
+    d_uns64 bitsPerWord = sz_size_t * 8;
+    d_uns64 cntptr = (sz + sz_size_t - 1) / sz_size_t;
+    d_uns64 cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord;
+    Array<d_uns64> data;
+    data.setDim((size_t)cntdata);
+    data.zero();
+
+    class PointerBitmapVisitor : public Visitor
+    {
+    public:
+        PointerBitmapVisitor(Array<d_uns64>* _data, d_uns64 _sz_size_t)
+            : data(_data), offset(0), sz_size_t(_sz_size_t), error(false)
+        {}
+
+        void setpointer(d_uns64 off)
+        {
+            d_uns64 ptroff = off / sz_size_t;
+            (*data)[(size_t)(ptroff / (8 * sz_size_t))] |= 1LL << (ptroff % (8 * sz_size_t));
+        }
+        virtual void visit(Type *t)
+        {
+            Type *tb = t->toBasetype();
+            if (tb != t)
+                tb->accept(this);
+        }
+        virtual void visit(TypeError *t) { visit((Type *)t); }
+        virtual void visit(TypeNext *t) { assert(0); }
+        virtual void visit(TypeBasic *t)
+        {
+            if (t->ty == Tvoid)
+                setpointer(offset);
+        }
+        virtual void visit(TypeVector *t) { }
+        virtual void visit(TypeArray *t) { assert(0); }
+        virtual void visit(TypeSArray *t)
+        {
+            d_uns64 arrayoff = offset;
+            d_uns64 nextsize = t->next->size();
+            if (nextsize == SIZE_INVALID)
+                error = true;
+            d_uns64 dim = t->dim->toInteger();
+            for (d_uns64 i = 0; i < dim; i++)
+            {
+                offset = arrayoff + i * nextsize;
+                t->next->accept(this);
+            }
+            offset = arrayoff;
+        }
+        virtual void visit(TypeDArray *t) { setpointer(offset + sz_size_t); } // dynamic array is {length,ptr}
+        virtual void visit(TypeAArray *t) { setpointer(offset); }
+        virtual void visit(TypePointer *t)
+        {
+            if (t->nextOf()->ty != Tfunction) // don't mark function pointers
+                setpointer(offset);
+        }
+        virtual void visit(TypeReference *t) { setpointer(offset); }
+        virtual void visit(TypeClass *t) { setpointer(offset); }
+        virtual void visit(TypeFunction *t) { }
+        virtual void visit(TypeDelegate *t) { setpointer(offset); } // delegate is {context, function}
+        virtual void visit(TypeQualified *t) { assert(0); } // assume resolved
+        virtual void visit(TypeIdentifier *t) { assert(0); }
+        virtual void visit(TypeInstance *t) { assert(0); }
+        virtual void visit(TypeTypeof *t) { assert(0); }
+        virtual void visit(TypeReturn *t) { assert(0); }
+        virtual void visit(TypeEnum *t) { visit((Type *)t); }
+        virtual void visit(TypeTuple *t) { visit((Type *)t); }
+        virtual void visit(TypeSlice *t) { assert(0); }
+        virtual void visit(TypeNull *t) { assert(0); }
+
+        virtual void visit(TypeStruct *t)
+        {
+            d_uns64 structoff = offset;
+            for (size_t i = 0; i < t->sym->fields.dim; i++)
+            {
+                VarDeclaration *v = t->sym->fields[i];
+                offset = structoff + v->offset;
+                if (v->type->ty == Tclass)
+                    setpointer(offset);
+                else
+                    v->type->accept(this);
+            }
+            offset = structoff;
+        }
+
+        // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references
+        void visitClass(TypeClass* t)
+        {
+            d_uns64 classoff = offset;
+
+            // skip vtable-ptr and monitor
+            if (t->sym->baseClass)
+                visitClass((TypeClass*)t->sym->baseClass->type);
+
+            for (size_t i = 0; i < t->sym->fields.dim; i++)
+            {
+                VarDeclaration *v = t->sym->fields[i];
+                offset = classoff + v->offset;
+                v->type->accept(this);
+            }
+            offset = classoff;
+        }
+
+        Array<d_uns64>* data;
+        d_uns64 offset;
+        d_uns64 sz_size_t;
+        bool error;
+    };
+
+    PointerBitmapVisitor pbv(&data, sz_size_t);
+    if (t->ty == Tclass)
+        pbv.visitClass((TypeClass*)t);
+    else
+        t->accept(&pbv);
+    if (pbv.error)
+        return new ErrorExp();
+
+    Expressions* exps = new Expressions;
+    exps->push(new IntegerExp(e->loc, sz, Type::tsize_t));
+    for (d_uns64 i = 0; i < cntdata; i++)
+        exps->push(new IntegerExp(e->loc, data[(size_t)i], Type::tsize_t));
+
+    ArrayLiteralExp* ale = new ArrayLiteralExp(e->loc, exps);
+    ale->type = Type::tsize_t->sarrayOf(cntdata + 1);
+    return ale;
+}
+
+static Expression *dimError(TraitsExp *e, int expected, int dim)
+{
+    e->error("expected %d arguments for `%s` but had %d", expected, e->ident->toChars(), dim);
+    return new ErrorExp();
+}
+
+Expression *semanticTraits(TraitsExp *e, Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("TraitsExp::semantic() %s\n", e->toChars());
+#endif
+    if (e->ident != Id::compiles && e->ident != Id::isSame &&
+        e->ident != Id::identifier && e->ident != Id::getProtection)
+    {
+        if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1))
+            return new ErrorExp();
+    }
+    size_t dim = e->args ? e->args->dim : 0;
+
+    if (e->ident == Id::isArithmetic)
+    {
+        return isTypeX(e, &isTypeArithmetic);
+    }
+    else if (e->ident == Id::isFloating)
+    {
+        return isTypeX(e, &isTypeFloating);
+    }
+    else if (e->ident == Id::isIntegral)
+    {
+        return isTypeX(e, &isTypeIntegral);
+    }
+    else if (e->ident == Id::isScalar)
+    {
+        return isTypeX(e, &isTypeScalar);
+    }
+    else if (e->ident == Id::isUnsigned)
+    {
+        return isTypeX(e, &isTypeUnsigned);
+    }
+    else if (e->ident == Id::isAssociativeArray)
+    {
+        return isTypeX(e, &isTypeAssociativeArray);
+    }
+    else if (e->ident == Id::isStaticArray)
+    {
+        return isTypeX(e, &isTypeStaticArray);
+    }
+    else if (e->ident == Id::isAbstractClass)
+    {
+        return isTypeX(e, &isTypeAbstractClass);
+    }
+    else if (e->ident == Id::isFinalClass)
+    {
+        return isTypeX(e, &isTypeFinalClass);
+    }
+    else if (e->ident == Id::isTemplate)
+    {
+        return isSymbolX(e, &isTemplate);
+    }
+    else if (e->ident == Id::isPOD)
+    {
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        RootObject *o = (*e->args)[0];
+        Type *t = isType(o);
+        if (!t)
+        {
+            e->error("type expected as second argument of __traits %s instead of %s",
+                e->ident->toChars(), o->toChars());
+            return new ErrorExp();
+        }
+
+        Type *tb = t->baseElemOf();
+        if (StructDeclaration *sd = (tb->ty == Tstruct) ? ((TypeStruct *)tb)->sym : NULL)
+        {
+            return (sd->isPOD()) ? True(e) : False(e);
+        }
+        return True(e);
+    }
+    else if (e->ident == Id::isNested)
+    {
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        RootObject *o = (*e->args)[0];
+        Dsymbol *s = getDsymbol(o);
+        if (!s)
+        {
+        }
+        else if (AggregateDeclaration *a = s->isAggregateDeclaration())
+        {
+            return a->isNested() ? True(e) : False(e);
+        }
+        else if (FuncDeclaration *f = s->isFuncDeclaration())
+        {
+            return f->isNested() ? True(e) : False(e);
+        }
+
+        e->error("aggregate or function expected instead of '%s'", o->toChars());
+        return new ErrorExp();
+    }
+    else if (e->ident == Id::isAbstractFunction)
+    {
+        return isFuncX(e, &isFuncAbstractFunction);
+    }
+    else if (e->ident == Id::isVirtualFunction)
+    {
+        return isFuncX(e, &isFuncVirtualFunction);
+    }
+    else if (e->ident == Id::isVirtualMethod)
+    {
+        return isFuncX(e, &isFuncVirtualMethod);
+    }
+    else if (e->ident == Id::isFinalFunction)
+    {
+        return isFuncX(e, &isFuncFinalFunction);
+    }
+    else if (e->ident == Id::isOverrideFunction)
+    {
+        return isFuncX(e, &isFuncOverrideFunction);
+    }
+    else if (e->ident == Id::isStaticFunction)
+    {
+        return isFuncX(e, &isFuncStaticFunction);
+    }
+    else if (e->ident == Id::isRef)
+    {
+        return isDeclX(e, &isDeclRef);
+    }
+    else if (e->ident == Id::isOut)
+    {
+        return isDeclX(e, &isDeclOut);
+    }
+    else if (e->ident == Id::isLazy)
+    {
+        return isDeclX(e, &isDeclLazy);
+    }
+    else if (e->ident == Id::identifier)
+    {
+        // Get identifier for symbol as a string literal
+        /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
+         * a symbol should not be folded to a constant.
+         * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
+         */
+        if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 2))
+            return new ErrorExp();
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        RootObject *o = (*e->args)[0];
+        Identifier *id = NULL;
+        if (Parameter *po = isParameter(o))
+        {
+            id = po->ident;
+            assert(id);
+        }
+        else
+        {
+            Dsymbol *s = getDsymbol(o);
+            if (!s || !s->ident)
+            {
+                e->error("argument %s has no identifier", o->toChars());
+                return new ErrorExp();
+            }
+            id = s->ident;
+        }
+
+        StringExp *se = new StringExp(e->loc, (char *)id->toChars());
+        return semantic(se, sc);
+    }
+    else if (e->ident == Id::getProtection)
+    {
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        Scope *sc2 = sc->push();
+        sc2->flags = sc->flags | SCOPEnoaccesscheck;
+        bool ok = TemplateInstance::semanticTiargs(e->loc, sc2, e->args, 1);
+        sc2->pop();
+        if (!ok)
+            return new ErrorExp();
+
+        RootObject *o = (*e->args)[0];
+        Dsymbol *s = getDsymbol(o);
+        if (!s)
+        {
+            if (!isError(o))
+                e->error("argument %s has no protection", o->toChars());
+            return new ErrorExp();
+        }
+        if (s->_scope)
+            s->semantic(s->_scope);
+
+        const char *protName = protectionToChars(s->prot().kind);   // TODO: How about package(names)
+        assert(protName);
+        StringExp *se = new StringExp(e->loc, (char *) protName);
+        return semantic(se, sc);
+    }
+    else if (e->ident == Id::parent)
+    {
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        RootObject *o = (*e->args)[0];
+        Dsymbol *s = getDsymbol(o);
+        if (s)
+        {
+            if (FuncDeclaration *fd = s->isFuncDeclaration())   // Bugzilla 8943
+                s = fd->toAliasFunc();
+            if (!s->isImport())  // Bugzilla 8922
+                s = s->toParent();
+        }
+        if (!s || s->isImport())
+        {
+            e->error("argument %s has no parent", o->toChars());
+            return new ErrorExp();
+        }
+
+        if (FuncDeclaration *f = s->isFuncDeclaration())
+        {
+            if (TemplateDeclaration *td = getFuncTemplateDecl(f))
+            {
+                if (td->overroot)       // if not start of overloaded list of TemplateDeclaration's
+                    td = td->overroot;  // then get the start
+                Expression *ex = new TemplateExp(e->loc, td, f);
+                ex = semantic(ex, sc);
+                return ex;
+            }
+
+            if (FuncLiteralDeclaration *fld = f->isFuncLiteralDeclaration())
+            {
+                // Directly translate to VarExp instead of FuncExp
+                Expression *ex = new VarExp(e->loc, fld, true);
+                return semantic(ex, sc);
+            }
+        }
+
+        return resolve(e->loc, sc, s, false);
+    }
+    else if (e->ident == Id::hasMember ||
+             e->ident == Id::getMember ||
+             e->ident == Id::getOverloads ||
+             e->ident == Id::getVirtualMethods ||
+             e->ident == Id::getVirtualFunctions)
+    {
+        if (dim != 2)
+            return dimError(e, 2, dim);
+
+        RootObject *o = (*e->args)[0];
+        Expression *ex = isExpression((*e->args)[1]);
+        if (!ex)
+        {
+            e->error("expression expected as second argument of __traits %s", e->ident->toChars());
+            return new ErrorExp();
+        }
+        ex = ex->ctfeInterpret();
+
+        StringExp *se = ex->toStringExp();
+        if (!se || se->len == 0)
+        {
+            e->error("string expected as second argument of __traits %s instead of %s", e->ident->toChars(), ex->toChars());
+            return new ErrorExp();
+        }
+        se = se->toUTF8(sc);
+
+        if (se->sz != 1)
+        {
+            e->error("string must be chars");
+            return new ErrorExp();
+        }
+        Identifier *id = Identifier::idPool((char *)se->string, se->len);
+
+        /* Prefer dsymbol, because it might need some runtime contexts.
+         */
+        Dsymbol *sym = getDsymbol(o);
+        if (sym)
+        {
+            ex = new DsymbolExp(e->loc, sym);
+            ex = new DotIdExp(e->loc, ex, id);
+        }
+        else if (Type *t = isType(o))
+            ex = typeDotIdExp(e->loc, t, id);
+        else if (Expression *ex2 = isExpression(o))
+            ex = new DotIdExp(e->loc, ex2, id);
+        else
+        {
+            e->error("invalid first argument");
+            return new ErrorExp();
+        }
+
+        if (e->ident == Id::hasMember)
+        {
+            if (sym)
+            {
+                if (Dsymbol *sm = sym->search(e->loc, id))
+                    return True(e);
+            }
+
+            /* Take any errors as meaning it wasn't found
+             */
+            Scope *scx = sc->push();
+            scx->flags |= SCOPEignoresymbolvisibility;
+            ex = trySemantic(ex, scx);
+            scx->pop();
+            return ex ? True(e) : False(e);
+        }
+        else if (e->ident == Id::getMember)
+        {
+            if (ex->op == TOKdotid)
+                // Prevent semantic() from replacing Symbol with its initializer
+                ((DotIdExp *)ex)->wantsym = true;
+            Scope *scx = sc->push();
+            scx->flags |= SCOPEignoresymbolvisibility;
+            ex = semantic(ex, scx);
+            scx->pop();
+            return ex;
+        }
+        else if (e->ident == Id::getVirtualFunctions ||
+                 e->ident == Id::getVirtualMethods ||
+                 e->ident == Id::getOverloads)
+        {
+            unsigned errors = global.errors;
+            Expression *eorig = ex;
+            Scope *scx = sc->push();
+            scx->flags |= SCOPEignoresymbolvisibility;
+            ex = semantic(ex, scx);
+            if (errors < global.errors)
+                e->error("%s cannot be resolved", eorig->toChars());
+            //ex->print();
+
+            /* Create tuple of functions of ex
+             */
+            Expressions *exps = new Expressions();
+            FuncDeclaration *f;
+            if (ex->op == TOKvar)
+            {
+                VarExp *ve = (VarExp *)ex;
+                f = ve->var->isFuncDeclaration();
+                ex = NULL;
+            }
+            else if (ex->op == TOKdotvar)
+            {
+                DotVarExp *dve = (DotVarExp *)ex;
+                f = dve->var->isFuncDeclaration();
+                if (dve->e1->op == TOKdottype || dve->e1->op == TOKthis)
+                    ex = NULL;
+                else
+                    ex = dve->e1;
+            }
+            else
+                f = NULL;
+            Ptrait p;
+            p.exps = exps;
+            p.e1 = ex;
+            p.ident = e->ident;
+            overloadApply(f, &p, &fptraits);
+
+            ex = new TupleExp(e->loc, exps);
+            ex = semantic(ex, scx);
+            scx->pop();
+            return ex;
+        }
+        else
+            assert(0);
+    }
+    else if (e->ident == Id::classInstanceSize)
+    {
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        RootObject *o = (*e->args)[0];
+        Dsymbol *s = getDsymbol(o);
+        ClassDeclaration *cd = s ? s->isClassDeclaration() : NULL;
+        if (!cd)
+        {
+            e->error("first argument is not a class");
+            return new ErrorExp();
+        }
+        if (cd->sizeok != SIZEOKdone)
+        {
+            cd->size(cd->loc);
+        }
+        if (cd->sizeok != SIZEOKdone)
+        {
+            e->error("%s %s is forward referenced", cd->kind(), cd->toChars());
+            return new ErrorExp();
+        }
+
+        return new IntegerExp(e->loc, cd->structsize, Type::tsize_t);
+    }
+    else if (e->ident == Id::getAliasThis)
+    {
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        RootObject *o = (*e->args)[0];
+        Dsymbol *s = getDsymbol(o);
+        AggregateDeclaration *ad = s ? s->isAggregateDeclaration() : NULL;
+        if (!ad)
+        {
+            e->error("argument is not an aggregate type");
+            return new ErrorExp();
+        }
+
+        Expressions *exps = new Expressions();
+        if (ad->aliasthis)
+            exps->push(new StringExp(e->loc, (char *)ad->aliasthis->ident->toChars()));
+        Expression *ex = new TupleExp(e->loc, exps);
+        ex = semantic(ex, sc);
+        return ex;
+    }
+    else if (e->ident == Id::getAttributes)
+    {
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        RootObject *o = (*e->args)[0];
+        Dsymbol *s = getDsymbol(o);
+        if (!s)
+        {
+        #if 0
+            Expression *x = isExpression(o);
+            Type *t = isType(o);
+            if (x)
+                printf("e = %s %s\n", Token::toChars(x->op), x->toChars());
+            if (t)
+                printf("t = %d %s\n", t->ty, t->toChars());
+        #endif
+            e->error("first argument is not a symbol");
+            return new ErrorExp();
+        }
+        if (Import *imp = s->isImport())
+        {
+            s = imp->mod;
+        }
+
+        //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->_scope);
+        UserAttributeDeclaration *udad = s->userAttribDecl;
+        Expressions *exps = udad ? udad->getAttributes() : new Expressions();
+        TupleExp *tup = new TupleExp(e->loc, exps);
+        return semantic(tup, sc);
+    }
+    else if (e->ident == Id::getFunctionAttributes)
+    {
+        /// extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs.
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        RootObject *o = (*e->args)[0];
+        Dsymbol *s = getDsymbol(o);
+        Type *t = isType(o);
+        TypeFunction *tf = NULL;
+        if (s)
+        {
+            if (FuncDeclaration *f = s->isFuncDeclaration())
+                t = f->type;
+            else if (VarDeclaration *v = s->isVarDeclaration())
+                t = v->type;
+        }
+        if (t)
+        {
+            if (t->ty == Tfunction)
+                tf = (TypeFunction *)t;
+            else if (t->ty == Tdelegate)
+                tf = (TypeFunction *)t->nextOf();
+            else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
+                tf = (TypeFunction *)t->nextOf();
+        }
+        if (!tf)
+        {
+            e->error("first argument is not a function");
+            return new ErrorExp();
+        }
+
+        Expressions *mods = new Expressions();
+        PushAttributes pa;
+        pa.mods = mods;
+        tf->modifiersApply(&pa, &PushAttributes::fp);
+        tf->attributesApply(&pa, &PushAttributes::fp, TRUSTformatSystem);
+
+        TupleExp *tup = new TupleExp(e->loc, mods);
+        return semantic(tup, sc);
+    }
+    else if (e->ident == Id::getFunctionVariadicStyle)
+    {
+        /* Accept a symbol or a type. Returns one of the following:
+         *  "none"      not a variadic function
+         *  "argptr"    extern(D) void dstyle(...), use `__argptr` and `__arguments`
+         *  "stdarg"    extern(C) void cstyle(int, ...), use core.stdc.stdarg
+         *  "typesafe"  void typesafe(T[] ...)
+         */
+        // get symbol linkage as a string
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        LINK link;
+        int varargs;
+        RootObject *o = (*e->args)[0];
+        Type *t = isType(o);
+        TypeFunction *tf = NULL;
+        if (t)
+        {
+            if (t->ty == Tfunction)
+                tf = (TypeFunction *)t;
+            else if (t->ty == Tdelegate)
+                tf = (TypeFunction *)t->nextOf();
+            else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
+                tf = (TypeFunction *)t->nextOf();
+        }
+        if (tf)
+        {
+            link = tf->linkage;
+            varargs = tf->varargs;
+        }
+        else
+        {
+            Dsymbol *s = getDsymbol(o);
+            FuncDeclaration *fd = NULL;
+            if (!s || (fd = s->isFuncDeclaration()) == NULL)
+            {
+                e->error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o->toChars());
+                return new ErrorExp();
+            }
+            link = fd->linkage;
+            fd->getParameters(&varargs);
+        }
+        const char *style;
+        switch (varargs)
+        {
+            case 0: style = "none";                      break;
+            case 1: style = (link == LINKd) ? "argptr"
+                                            : "stdarg";  break;
+            case 2:     style = "typesafe";              break;
+            default:
+                assert(0);
+        }
+        StringExp *se = new StringExp(e->loc, (char*)style);
+        return semantic(se, sc);
+    }
+    else if (e->ident == Id::getParameterStorageClasses)
+    {
+        /* Accept a function symbol or a type, followed by a parameter index.
+         * Returns a tuple of strings of the parameter's storage classes.
+         */
+        // get symbol linkage as a string
+        if (dim != 2)
+            return dimError(e, 2, dim);
+
+        RootObject *o1 = (*e->args)[1];
+        RootObject *o = (*e->args)[0];
+        Type *t = isType(o);
+        TypeFunction *tf = NULL;
+        if (t)
+        {
+            if (t->ty == Tfunction)
+                tf = (TypeFunction *)t;
+            else if (t->ty == Tdelegate)
+                tf = (TypeFunction *)t->nextOf();
+            else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
+                tf = (TypeFunction *)t->nextOf();
+        }
+        Parameters* fparams;
+        if (tf)
+        {
+            fparams = tf->parameters;
+        }
+        else
+        {
+            Dsymbol *s = getDsymbol(o);
+            FuncDeclaration *fd = NULL;
+            if (!s || (fd = s->isFuncDeclaration()) == NULL)
+            {
+                e->error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function",
+                    o->toChars(), o1->toChars());
+                return new ErrorExp();
+            }
+            fparams = fd->getParameters(NULL);
+        }
+
+        StorageClass stc;
+
+        // Set stc to storage class of the ith parameter
+        Expression *ex = isExpression((*e->args)[1]);
+        if (!ex)
+        {
+            e->error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`",
+                o->toChars(), o1->toChars());
+            return new ErrorExp();
+        }
+        ex = ex->ctfeInterpret();
+        uinteger_t ii = ex->toUInteger();
+        if (ii >= Parameter::dim(fparams))
+        {
+            e->error("parameter index must be in range 0..%u not %s", (unsigned)Parameter::dim(fparams), ex->toChars());
+            return new ErrorExp();
+        }
+
+        unsigned n = (unsigned)ii;
+        Parameter *p = Parameter::getNth(fparams, n);
+        stc = p->storageClass;
+
+        // This mirrors hdrgen.visit(Parameter p)
+        if (p->type && p->type->mod & MODshared)
+            stc &= ~STCshared;
+
+        Expressions *exps = new Expressions;
+
+        if (stc & STCauto)
+            exps->push(new StringExp(e->loc, (char *)"auto"));
+        if (stc & STCreturn)
+            exps->push(new StringExp(e->loc, (char *)"return"));
+
+        if (stc & STCout)
+            exps->push(new StringExp(e->loc, (char *)"out"));
+        else if (stc & STCref)
+            exps->push(new StringExp(e->loc, (char *)"ref"));
+        else if (stc & STCin)
+            exps->push(new StringExp(e->loc, (char *)"in"));
+        else if (stc & STClazy)
+            exps->push(new StringExp(e->loc, (char *)"lazy"));
+        else if (stc & STCalias)
+            exps->push(new StringExp(e->loc, (char *)"alias"));
+
+        if (stc & STCconst)
+            exps->push(new StringExp(e->loc, (char *)"const"));
+        if (stc & STCimmutable)
+            exps->push(new StringExp(e->loc, (char *)"immutable"));
+        if (stc & STCwild)
+            exps->push(new StringExp(e->loc, (char *)"inout"));
+        if (stc & STCshared)
+            exps->push(new StringExp(e->loc, (char *)"shared"));
+        if (stc & STCscope && !(stc & STCscopeinferred))
+            exps->push(new StringExp(e->loc, (char *)"scope"));
+
+        TupleExp *tup = new TupleExp(e->loc, exps);
+        return semantic(tup, sc);
+    }
+    else if (e->ident == Id::getLinkage)
+    {
+        // get symbol linkage as a string
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        LINK link;
+        RootObject *o = (*e->args)[0];
+        Type *t = isType(o);
+        TypeFunction *tf = NULL;
+        if (t)
+        {
+            if (t->ty == Tfunction)
+                tf = (TypeFunction *)t;
+            else if (t->ty == Tdelegate)
+                tf = (TypeFunction *)t->nextOf();
+            else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
+                tf = (TypeFunction *)t->nextOf();
+        }
+        if (tf)
+            link = tf->linkage;
+        else
+        {
+            Dsymbol *s = getDsymbol(o);
+            Declaration *d = NULL;
+            if (!s || (d = s->isDeclaration()) == NULL)
+            {
+                e->error("argument to `__traits(getLinkage, %s)` is not a declaration", o->toChars());
+                return new ErrorExp();
+            }
+            link = d->linkage;
+        }
+        const char *linkage = linkageToChars(link);
+        StringExp *se = new StringExp(e->loc, (char *)linkage);
+        return semantic(se, sc);
+    }
+    else if (e->ident == Id::allMembers ||
+             e->ident == Id::derivedMembers)
+    {
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        RootObject *o = (*e->args)[0];
+        Dsymbol *s = getDsymbol(o);
+        if (!s)
+        {
+            e->error("argument has no members");
+            return new ErrorExp();
+        }
+        if (Import *imp = s->isImport())
+        {
+            // Bugzilla 9692
+            s = imp->mod;
+        }
+
+        ScopeDsymbol *sds = s->isScopeDsymbol();
+        if (!sds || sds->isTemplateDeclaration())
+        {
+            e->error("%s %s has no members", s->kind(), s->toChars());
+            return new ErrorExp();
+        }
+
+        // use a struct as local function
+        struct PushIdentsDg
+        {
+            static int dg(void *ctx, size_t n, Dsymbol *sm)
+            {
+                if (!sm)
+                    return 1;
+                //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
+                if (sm->ident)
+                {
+                    const char *idx = sm->ident->toChars();
+                    if (idx[0] == '_' && idx[1] == '_' &&
+                        sm->ident != Id::ctor &&
+                        sm->ident != Id::dtor &&
+                        sm->ident != Id::__xdtor &&
+                        sm->ident != Id::postblit &&
+                        sm->ident != Id::__xpostblit)
+                    {
+                        return 0;
+                    }
+
+                    if (sm->ident == Id::empty)
+                    {
+                        return 0;
+                    }
+                    if (sm->isTypeInfoDeclaration()) // Bugzilla 15177
+                        return 0;
+
+                    //printf("\t%s\n", sm->ident->toChars());
+                    Identifiers *idents = (Identifiers *)ctx;
+
+                    /* Skip if already present in idents[]
+                     */
+                    for (size_t j = 0; j < idents->dim; j++)
+                    {
+                        Identifier *id = (*idents)[j];
+                        if (id == sm->ident)
+                            return 0;
+#ifdef DEBUG
+                        // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop.
+                        assert(strcmp(id->toChars(), sm->ident->toChars()) != 0);
+#endif
+                    }
+
+                    idents->push(sm->ident);
+                }
+                else
+                {
+                    EnumDeclaration *ed = sm->isEnumDeclaration();
+                    if (ed)
+                    {
+                        ScopeDsymbol_foreach(NULL, ed->members, &PushIdentsDg::dg, (Identifiers *)ctx);
+                    }
+                }
+                return 0;
+            }
+        };
+
+        Identifiers *idents = new Identifiers;
+        ScopeDsymbol_foreach(sc, sds->members, &PushIdentsDg::dg, idents);
+        ClassDeclaration *cd = sds->isClassDeclaration();
+        if (cd && e->ident == Id::allMembers)
+        {
+            if (cd->_scope)
+                cd->semantic(NULL);    // Bugzilla 13668: Try to resolve forward reference
+
+            struct PushBaseMembers
+            {
+                static void dg(ClassDeclaration *cd, Identifiers *idents)
+                {
+                    for (size_t i = 0; i < cd->baseclasses->dim; i++)
+                    {
+                        ClassDeclaration *cb = (*cd->baseclasses)[i]->sym;
+                        assert(cb);
+                        ScopeDsymbol_foreach(NULL, cb->members, &PushIdentsDg::dg, idents);
+                        if (cb->baseclasses->dim)
+                            dg(cb, idents);
+                    }
+                }
+            };
+            PushBaseMembers::dg(cd, idents);
+        }
+
+        // Turn Identifiers into StringExps reusing the allocated array
+        assert(sizeof(Expressions) == sizeof(Identifiers));
+        Expressions *exps = (Expressions *)idents;
+        for (size_t i = 0; i < idents->dim; i++)
+        {
+            Identifier *id = (*idents)[i];
+            StringExp *se = new StringExp(e->loc, (char *)id->toChars());
+            (*exps)[i] = se;
+        }
+
+        /* Making this a tuple is more flexible, as it can be statically unrolled.
+         * To make an array literal, enclose __traits in [ ]:
+         *   [ __traits(allMembers, ...) ]
+         */
+        Expression *ex = new TupleExp(e->loc, exps);
+        ex = semantic(ex, sc);
+        return ex;
+    }
+    else if (e->ident == Id::compiles)
+    {
+        /* Determine if all the objects - types, expressions, or symbols -
+         * compile without error
+         */
+        if (!dim)
+            return False(e);
+
+        for (size_t i = 0; i < dim; i++)
+        {
+            unsigned errors = global.startGagging();
+            Scope *sc2 = sc->push();
+            sc2->tinst = NULL;
+            sc2->minst = NULL;
+            sc2->flags = (sc->flags & ~(SCOPEctfe | SCOPEcondition)) | SCOPEcompile | SCOPEfullinst;
+            bool err = false;
+
+            RootObject *o = (*e->args)[i];
+            Type *t = isType(o);
+            Expression *ex = t ? typeToExpression(t) : isExpression(o);
+            if (!ex && t)
+            {
+                Dsymbol *s;
+                t->resolve(e->loc, sc2, &ex, &t, &s);
+                if (t)
+                {
+                    t->semantic(e->loc, sc2);
+                    if (t->ty == Terror)
+                        err = true;
+                }
+                else if (s && s->errors)
+                    err = true;
+            }
+            if (ex)
+            {
+                ex = semantic(ex, sc2);
+                ex = resolvePropertiesOnly(sc2, ex);
+                ex = ex->optimize(WANTvalue);
+                if (sc2->func && sc2->func->type->ty == Tfunction)
+                {
+                    TypeFunction *tf = (TypeFunction *)sc2->func->type;
+                    canThrow(ex, sc2->func, tf->isnothrow);
+                }
+                ex = checkGC(sc2, ex);
+                if (ex->op == TOKerror)
+                    err = true;
+            }
+
+            // Carefully detach the scope from the parent and throw it away as
+            // we only need it to evaluate the expression
+            // https://issues.dlang.org/show_bug.cgi?id=15428
+            freeFieldinit(sc2);
+            sc2->enclosing = NULL;
+            sc2->pop();
+
+            if (global.endGagging(errors) || err)
+            {
+                return False(e);
+            }
+        }
+        return True(e);
+    }
+    else if (e->ident == Id::isSame)
+    {
+        /* Determine if two symbols are the same
+         */
+        if (dim != 2)
+            return dimError(e, 2, dim);
+
+        if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 0))
+            return new ErrorExp();
+
+        RootObject *o1 = (*e->args)[0];
+        RootObject *o2 = (*e->args)[1];
+        Dsymbol *s1 = getDsymbol(o1);
+        Dsymbol *s2 = getDsymbol(o2);
+        //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars());
+#if 0
+        printf("o1: %p\n", o1);
+        printf("o2: %p\n", o2);
+        if (!s1)
+        {
+            Expression *ea = isExpression(o1);
+            if (ea)
+                printf("%s\n", ea->toChars());
+            Type *ta = isType(o1);
+            if (ta)
+                printf("%s\n", ta->toChars());
+            return False(e);
+        }
+        else
+            printf("%s %s\n", s1->kind(), s1->toChars());
+#endif
+        if (!s1 && !s2)
+        {
+            Expression *ea1 = isExpression(o1);
+            Expression *ea2 = isExpression(o2);
+            if (ea1 && ea2)
+            {
+                if (ea1->equals(ea2))
+                    return True(e);
+            }
+        }
+        if (!s1 || !s2)
+            return False(e);
+        s1 = s1->toAlias();
+        s2 = s2->toAlias();
+
+        if (s1->isFuncAliasDeclaration())
+            s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc();
+        if (s2->isFuncAliasDeclaration())
+            s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc();
+
+        return (s1 == s2) ? True(e) : False(e);
+    }
+    else if (e->ident == Id::getUnitTests)
+    {
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        RootObject *o = (*e->args)[0];
+        Dsymbol *s = getDsymbol(o);
+        if (!s)
+        {
+            e->error("argument %s to __traits(getUnitTests) must be a module or aggregate",
+                o->toChars());
+            return new ErrorExp();
+        }
+        if (Import *imp = s->isImport())  // Bugzilla 10990
+            s = imp->mod;
+
+        ScopeDsymbol* sds = s->isScopeDsymbol();
+        if (!sds)
+        {
+            e->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s",
+                s->toChars(), s->kind());
+            return new ErrorExp();
+        }
+
+        Expressions *exps = new Expressions();
+        if (global.params.useUnitTests)
+        {
+            // Should actually be a set
+            AA* uniqueUnitTests = NULL;
+            collectUnitTests(sds->members, uniqueUnitTests, exps);
+        }
+        TupleExp *te= new TupleExp(e->loc, exps);
+        return semantic(te, sc);
+    }
+    else if(e->ident == Id::getVirtualIndex)
+    {
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        RootObject *o = (*e->args)[0];
+        Dsymbol *s = getDsymbol(o);
+
+        FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
+        if (!fd)
+        {
+            e->error("first argument to __traits(getVirtualIndex) must be a function");
+            return new ErrorExp();
+        }
+
+        fd = fd->toAliasFunc(); // Neccessary to support multiple overloads.
+        return new IntegerExp(e->loc, fd->vtblIndex, Type::tptrdiff_t);
+    }
+    else if (e->ident == Id::getPointerBitmap)
+    {
+        return pointerBitmap(e);
+    }
+
+    if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars))
+        e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub);
+    else
+        e->error("unrecognized trait '%s'", e->ident->toChars());
+    return new ErrorExp();
+
+Ldimerror:
+    e->error("wrong number of arguments %d", (int)dim);
+    return new ErrorExp();
+}
diff --git a/gcc/d/dfrontend/typesem.c b/gcc/d/dfrontend/typesem.c
new file mode 100644
index 00000000000..4e88c18fd2b
--- /dev/null
+++ b/gcc/d/dfrontend/typesem.c
@@ -0,0 +1,124 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2017 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+#include "mtype.h"
+#include "expression.h"
+#include "template.h"
+
+Expression *typeToExpression(Type *t);
+Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
+
+class TypeToExpressionVisitor : public Visitor
+{
+public:
+    Expression *result;
+    Type *itype;
+
+    TypeToExpressionVisitor(Type *itype)
+    {
+        this->result = NULL;
+        this->itype = itype;
+    }
+
+    void visit(Type *t)
+    {
+        result = NULL;
+    }
+
+    void visit(TypeSArray *t)
+    {
+        Expression *e = typeToExpression(t->next);
+        if (e)
+            e = new ArrayExp(t->dim->loc, e, t->dim);
+        result = e;
+    }
+
+    void visit(TypeAArray *t)
+    {
+        Expression *e = typeToExpression(t->next);
+        if (e)
+        {
+            Expression *ei = typeToExpression(t->index);
+            if (ei)
+            {
+                result = new ArrayExp(t->loc, e, ei);
+                return;
+            }
+        }
+        result = NULL;
+    }
+
+    void visit(TypeIdentifier *t)
+    {
+        result = typeToExpressionHelper(t, new IdentifierExp(t->loc, t->ident));
+    }
+
+    void visit(TypeInstance *t)
+    {
+        result = typeToExpressionHelper(t, new ScopeExp(t->loc, t->tempinst));
+    }
+};
+
+/* We've mistakenly parsed this as a type.
+ * Redo it as an Expression.
+ * NULL if cannot.
+ */
+Expression *typeToExpression(Type *t)
+{
+    TypeToExpressionVisitor v = TypeToExpressionVisitor(t);
+    t->accept(&v);
+    return v.result;
+}
+
+/* Helper function for `typeToExpression`. Contains common code
+ * for TypeQualified derived classes.
+ */
+Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i)
+{
+    //printf("toExpressionHelper(e = %s %s)\n", Token::toChars(e->op), e->toChars());
+    for (; i < t->idents.dim; i++)
+    {
+        RootObject *id = t->idents[i];
+        //printf("\t[%d] e: '%s', id: '%s'\n", i, e->toChars(), id->toChars());
+
+        switch (id->dyncast())
+        {
+            case DYNCAST_IDENTIFIER:
+            {
+                // ... '. ident'
+                e = new DotIdExp(e->loc, e, (Identifier *)id);
+                break;
+            }
+            case DYNCAST_DSYMBOL:
+            {
+                // ... '. name!(tiargs)'
+                TemplateInstance *ti = ((Dsymbol *)id)->isTemplateInstance();
+                assert(ti);
+                e = new DotTemplateInstanceExp(e->loc, e, ti->name, ti->tiargs);
+                break;
+            }
+            case DYNCAST_TYPE:          // Bugzilla 1215
+            {
+                // ... '[type]'
+                e = new ArrayExp(t->loc, e, new TypeExp(t->loc, (Type *)id));
+                break;
+            }
+            case DYNCAST_EXPRESSION:    // Bugzilla 1215
+            {
+                // ... '[expr]'
+                e = new ArrayExp(t->loc, e, (Expression *)id);
+                break;
+            }
+            default:
+                assert(0);
+        }
+    }
+    return e;
+}
diff --git a/gcc/d/dfrontend/unittests.c b/gcc/d/dfrontend/unittests.c
new file mode 100644
index 00000000000..47f7ca330c3
--- /dev/null
+++ b/gcc/d/dfrontend/unittests.c
@@ -0,0 +1,27 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/unittests.c
+ */
+
+#include <stdio.h>
+
+#include "mars.h"
+
+void unittest_speller();
+void unittest_importHint();
+void unittest_aa();
+
+void unittests()
+{
+#if UNITTEST
+    unittest_speller();
+    unittest_importHint();
+    unittest_aa();
+#endif
+}
diff --git a/gcc/d/dfrontend/utf.c b/gcc/d/dfrontend/utf.c
new file mode 100644
index 00000000000..fa47285c6d5
--- /dev/null
+++ b/gcc/d/dfrontend/utf.c
@@ -0,0 +1,305 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 2003-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/utf.c
+ */
+
+/// Description of UTF-8 in [1].  Unicode non-characters and private-use
+/// code points described in [2],[4].
+///
+/// References:
+/// [1] http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+/// [2] http://en.wikipedia.org/wiki/Unicode
+/// [3] http://unicode.org/faq/utf_bom.html
+/// [4] http://www.unicode.org/versions/Unicode6.1.0/ch03.pdf
+
+#include <assert.h>
+
+#include "utf.h"
+
+/* The following encodings are valid, except for the 5 and 6 byte
+ * combinations:
+ *      0xxxxxxx
+ *      110xxxxx 10xxxxxx
+ *      1110xxxx 10xxxxxx 10xxxxxx
+ *      11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ *      111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ *      1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ */
+const unsigned UTF8_STRIDE[256] =
+{
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+    4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF,
+};
+
+// UTF-8 decoding errors
+char const UTF8_DECODE_OUTSIDE_CODE_SPACE[] = "Outside Unicode code space";
+char const UTF8_DECODE_TRUNCATED_SEQUENCE[] = "Truncated UTF-8 sequence";
+char const UTF8_DECODE_OVERLONG[]           = "Overlong UTF-8 sequence";
+char const UTF8_DECODE_INVALID_TRAILER[]    = "Invalid trailing code unit";
+char const UTF8_DECODE_INVALID_CODE_POINT[] = "Invalid code point decoded";
+
+// UTF-16 decoding errors
+char const UTF16_DECODE_TRUNCATED_SEQUENCE[]= "Truncated UTF-16 sequence";
+char const UTF16_DECODE_INVALID_SURROGATE[] = "Invalid low surrogate";
+char const UTF16_DECODE_UNPAIRED_SURROGATE[]= "Unpaired surrogate";
+char const UTF16_DECODE_INVALID_CODE_POINT[]= "Invalid code point decoded";
+
+/// The Unicode code space is the range of code points [0x000000,0x10FFFF]
+/// except the UTF-16 surrogate pairs in the range [0xD800,0xDFFF]
+/// and non-characters (which end in 0xFFFE or 0xFFFF).
+bool utf_isValidDchar(dchar_t c)
+{
+    // TODO: Whether non-char code points should be rejected is pending review
+    // largest character code point
+    if (c > 0x10FFFF)
+        return false;
+    // surrogate pairs
+    if (0xD800 <= c && c <= 0xDFFF)
+        return false;
+    // non-characters
+    if ((c & 0xFFFFFE) == 0x00FFFE)
+        return false;
+    return true;
+}
+
+/*******************************
+ * Return !=0 if unicode alpha.
+ * Use table from C99 Appendix D.
+ */
+
+bool isUniAlpha(dchar_t c)
+{
+    size_t high = ALPHA_TABLE_LENGTH - 1;
+    // Shortcut search if c is out of range
+    size_t low
+        = (c < ALPHA_TABLE[0][0] || ALPHA_TABLE[high][1] < c) ? high + 1 : 0;
+    // Binary search
+    while (low <= high)
+    {
+        size_t mid = (low + high) >> 1;
+        if (c < ALPHA_TABLE[mid][0])
+            high = mid - 1;
+        else if (ALPHA_TABLE[mid][1] < c)
+            low = mid + 1;
+        else
+        {
+            assert(ALPHA_TABLE[mid][0] <= c && c <= ALPHA_TABLE[mid][1]);
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * Returns the code length of c in code units.
+ */
+
+int utf_codeLengthChar(dchar_t c)
+{
+    return
+        c <= 0x7F ? 1
+        : c <= 0x7FF ? 2
+        : c <= 0xFFFF ? 3
+        : c <= 0x10FFFF ? 4
+        : (assert(false), 6);
+}
+
+int utf_codeLengthWchar(dchar_t c)
+{
+    return c <= 0xFFFF ? 1 : 2;
+}
+
+/**
+ * Returns the code length of c in code units for the encoding.
+ * sz is the encoding: 1 = utf8, 2 = utf16, 4 = utf32.
+ */
+
+int utf_codeLength(int sz, dchar_t c)
+{
+    if (sz == 1)
+        return utf_codeLengthChar(c);
+    if (sz == 2)
+        return utf_codeLengthWchar(c);
+    assert(sz == 4);
+    return 1;
+}
+
+void utf_encodeChar(utf8_t *s, dchar_t c)
+{
+    assert(s != NULL);
+    assert(utf_isValidDchar(c));
+    if (c <= 0x7F)
+    {
+        s[0] = static_cast<utf8_t>(c);
+    }
+    else if (c <= 0x07FF)
+    {
+        s[0] = static_cast<utf8_t>(0xC0 | (c >> 6));
+        s[1] = static_cast<utf8_t>(0x80 | (c & 0x3F));
+    }
+    else if (c <= 0xFFFF)
+    {
+        s[0] = static_cast<utf8_t>(0xE0 | (c >> 12));
+        s[1] = static_cast<utf8_t>(0x80 | ((c >> 6) & 0x3F));
+        s[2] = static_cast<utf8_t>(0x80 | (c & 0x3F));
+    }
+    else if (c <= 0x10FFFF)
+    {
+        s[0] = static_cast<utf8_t>(0xF0 | (c >> 18));
+        s[1] = static_cast<utf8_t>(0x80 | ((c >> 12) & 0x3F));
+        s[2] = static_cast<utf8_t>(0x80 | ((c >> 6) & 0x3F));
+        s[3] = static_cast<utf8_t>(0x80 | (c & 0x3F));
+    }
+    else
+        assert(0);
+}
+
+void utf_encodeWchar(utf16_t *s, dchar_t c)
+{
+    assert(s != NULL);
+    assert(utf_isValidDchar(c));
+    if (c <= 0xFFFF)
+    {
+        s[0] = static_cast<utf16_t>(c);
+    }
+    else
+    {
+        s[0] = static_cast<utf16_t>((((c - 0x010000) >> 10) & 0x03FF) + 0xD800);
+        s[1] = static_cast<utf16_t>(((c - 0x010000) & 0x03FF) + 0xDC00);
+    }
+}
+
+void utf_encode(int sz, void *s, dchar_t c)
+{
+    if (sz == 1)
+        utf_encodeChar((utf8_t *)s, c);
+    else if (sz == 2)
+        utf_encodeWchar((utf16_t *)s, c);
+    else
+    {
+        assert(sz == 4);
+        *((utf32_t *)s) = c;
+    }
+}
+
+/********************************************
+ * Decode a UTF-8 sequence as a single UTF-32 code point.
+ * Returns:
+ *      NULL    success
+ *      !=NULL  error message string
+ */
+
+const char *utf_decodeChar(utf8_t const *s, size_t len, size_t *pidx, dchar_t *presult)
+{
+    assert(s != NULL);
+    assert(pidx != NULL);
+    assert(presult != NULL);
+    size_t i = (*pidx)++;
+    assert(i < len);
+    utf8_t u = s[i];
+    // Pre-stage results for ASCII and error cases
+    *presult = u;
+
+    //printf("utf_decodeChar(s = %02x, %02x, %02x len = %d)\n", u, s[1], s[2], len);
+
+    // Get expected sequence length
+    size_t n = UTF8_STRIDE[u];
+    switch (n)
+    {
+    case 1:                             // ASCII
+        return UTF8_DECODE_OK;
+    case 2: case 3: case 4:             // multi-byte UTF-8
+        break;
+    default:                            // 5- or 6-byte sequence
+        return UTF8_DECODE_OUTSIDE_CODE_SPACE;
+    }
+    if (len < i + n)                    // source too short
+        return UTF8_DECODE_TRUNCATED_SEQUENCE;
+
+    // Pick off 7 - n low bits from first code unit
+    utf32_t c = u & ((1 << (7 - n)) - 1);
+    /* The following combinations are overlong, and illegal:
+     *      1100000x (10xxxxxx)
+     *      11100000 100xxxxx (10xxxxxx)
+     *      11110000 1000xxxx (10xxxxxx 10xxxxxx)
+     *      11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
+     *      11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+     */
+    utf8_t u2 = s[++i];
+    // overlong combination
+    if ((u & 0xFE) == 0xC0 ||
+        (u == 0xE0 && (u2 & 0xE0) == 0x80) ||
+        (u == 0xF0 && (u2 & 0xF0) == 0x80) ||
+        (u == 0xF8 && (u2 & 0xF8) == 0x80) ||
+        (u == 0xFC && (u2 & 0xFC) == 0x80))
+        return UTF8_DECODE_OVERLONG;
+    // Decode remaining bits
+    for (n += i - 1; i != n; ++i)
+    {
+        u = s[i];
+        if ((u & 0xC0) != 0x80)         // trailing bytes are 10xxxxxx
+            return UTF8_DECODE_INVALID_TRAILER;
+        c = (c << 6) | (u & 0x3F);
+    }
+    if (!utf_isValidDchar(c))
+        return UTF8_DECODE_INVALID_CODE_POINT;
+    *pidx = i;
+    *presult = c;
+    return UTF8_DECODE_OK;
+}
+
+/********************************************
+ * Decode a UTF-16 sequence as a single UTF-32 code point.
+ * Returns:
+ *      NULL    success
+ *      !=NULL  error message string
+ */
+
+const char *utf_decodeWchar(utf16_t const *s, size_t len, size_t *pidx, dchar_t *presult)
+{
+    assert(s != NULL);
+    assert(pidx != NULL);
+    assert(presult != NULL);
+    size_t i = (*pidx)++;
+    assert(i < len);
+    // Pre-stage results for ASCII and error cases
+    utf32_t u = *presult = s[i];
+
+    if (u < 0x80)                       // ASCII
+        return UTF16_DECODE_OK;
+    if (0xD800 <= u && u <= 0xDBFF)     // Surrogate pair
+    {   if (len <= i + 1)
+            return UTF16_DECODE_TRUNCATED_SEQUENCE;
+        utf16_t u2 = s[i + 1];
+        if (u2 < 0xDC00 || 0xDFFF < u)
+            return UTF16_DECODE_INVALID_SURROGATE;
+        u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00);
+        ++*pidx;
+    }
+    else if (0xDC00 <= u && u <= 0xDFFF)
+        return UTF16_DECODE_UNPAIRED_SURROGATE;
+    if (!utf_isValidDchar(u))
+        return UTF16_DECODE_INVALID_CODE_POINT;
+    *presult = u;
+    return UTF16_DECODE_OK;
+}
diff --git a/gcc/d/dfrontend/utf.h b/gcc/d/dfrontend/utf.h
new file mode 100644
index 00000000000..b0ee25d5c74
--- /dev/null
+++ b/gcc/d/dfrontend/utf.h
@@ -0,0 +1,121 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 2003-2014 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/utf.h
+ */
+
+#ifndef DMD_UTF_H
+#define DMD_UTF_H
+
+#include <stdlib.h>
+
+/// A UTF-8 code unit
+typedef unsigned char   utf8_t;
+/// A UTF-16 code unit
+typedef unsigned short  utf16_t;
+/// A UTF-32 code unit
+typedef unsigned int    utf32_t;
+typedef utf32_t         dchar_t;
+
+#define ALPHA_TABLE_LENGTH 245
+static utf16_t const ALPHA_TABLE[ALPHA_TABLE_LENGTH][2] =
+{
+    { 0x00AA, 0x00AA }, { 0x00B5, 0x00B5 }, { 0x00B7, 0x00B7 }, { 0x00BA, 0x00BA },
+    { 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 }, { 0x00F8, 0x01F5 }, { 0x01FA, 0x0217 },
+    { 0x0250, 0x02A8 }, { 0x02B0, 0x02B8 }, { 0x02BB, 0x02BB }, { 0x02BD, 0x02C1 },
+    { 0x02D0, 0x02D1 }, { 0x02E0, 0x02E4 }, { 0x037A, 0x037A }, { 0x0386, 0x0386 },
+    { 0x0388, 0x038A }, { 0x038C, 0x038C }, { 0x038E, 0x03A1 }, { 0x03A3, 0x03CE },
+    { 0x03D0, 0x03D6 }, { 0x03DA, 0x03DA }, { 0x03DC, 0x03DC }, { 0x03DE, 0x03DE },
+    { 0x03E0, 0x03E0 }, { 0x03E2, 0x03F3 }, { 0x0401, 0x040C }, { 0x040E, 0x044F },
+    { 0x0451, 0x045C }, { 0x045E, 0x0481 }, { 0x0490, 0x04C4 }, { 0x04C7, 0x04C8 },
+    { 0x04CB, 0x04CC }, { 0x04D0, 0x04EB }, { 0x04EE, 0x04F5 }, { 0x04F8, 0x04F9 },
+    { 0x0531, 0x0556 }, { 0x0559, 0x0559 }, { 0x0561, 0x0587 }, { 0x05B0, 0x05B9 },
+    { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05D0, 0x05EA },
+    { 0x05F0, 0x05F2 }, { 0x0621, 0x063A }, { 0x0640, 0x0652 }, { 0x0660, 0x0669 },
+    { 0x0670, 0x06B7 }, { 0x06BA, 0x06BE }, { 0x06C0, 0x06CE }, { 0x06D0, 0x06DC },
+    { 0x06E5, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x06F0, 0x06F9 }, { 0x0901, 0x0903 },
+    { 0x0905, 0x0939 }, { 0x093D, 0x094D }, { 0x0950, 0x0952 }, { 0x0958, 0x0963 },
+    { 0x0966, 0x096F }, { 0x0981, 0x0983 }, { 0x0985, 0x098C }, { 0x098F, 0x0990 },
+    { 0x0993, 0x09A8 }, { 0x09AA, 0x09B0 }, { 0x09B2, 0x09B2 }, { 0x09B6, 0x09B9 },
+    { 0x09BE, 0x09C4 }, { 0x09C7, 0x09C8 }, { 0x09CB, 0x09CD }, { 0x09DC, 0x09DD },
+    { 0x09DF, 0x09E3 }, { 0x09E6, 0x09F1 }, { 0x0A02, 0x0A02 }, { 0x0A05, 0x0A0A },
+    { 0x0A0F, 0x0A10 }, { 0x0A13, 0x0A28 }, { 0x0A2A, 0x0A30 }, { 0x0A32, 0x0A33 },
+    { 0x0A35, 0x0A36 }, { 0x0A38, 0x0A39 }, { 0x0A3E, 0x0A42 }, { 0x0A47, 0x0A48 },
+    { 0x0A4B, 0x0A4D }, { 0x0A59, 0x0A5C }, { 0x0A5E, 0x0A5E }, { 0x0A66, 0x0A6F },
+    { 0x0A74, 0x0A74 }, { 0x0A81, 0x0A83 }, { 0x0A85, 0x0A8B }, { 0x0A8D, 0x0A8D },
+    { 0x0A8F, 0x0A91 }, { 0x0A93, 0x0AA8 }, { 0x0AAA, 0x0AB0 }, { 0x0AB2, 0x0AB3 },
+    { 0x0AB5, 0x0AB9 }, { 0x0ABD, 0x0AC5 }, { 0x0AC7, 0x0AC9 }, { 0x0ACB, 0x0ACD },
+    { 0x0AD0, 0x0AD0 }, { 0x0AE0, 0x0AE0 }, { 0x0AE6, 0x0AEF }, { 0x0B01, 0x0B03 },
+    { 0x0B05, 0x0B0C }, { 0x0B0F, 0x0B10 }, { 0x0B13, 0x0B28 }, { 0x0B2A, 0x0B30 },
+    { 0x0B32, 0x0B33 }, { 0x0B36, 0x0B39 }, { 0x0B3D, 0x0B43 }, { 0x0B47, 0x0B48 },
+    { 0x0B4B, 0x0B4D }, { 0x0B5C, 0x0B5D }, { 0x0B5F, 0x0B61 }, { 0x0B66, 0x0B6F },
+    { 0x0B82, 0x0B83 }, { 0x0B85, 0x0B8A }, { 0x0B8E, 0x0B90 }, { 0x0B92, 0x0B95 },
+    { 0x0B99, 0x0B9A }, { 0x0B9C, 0x0B9C }, { 0x0B9E, 0x0B9F }, { 0x0BA3, 0x0BA4 },
+    { 0x0BA8, 0x0BAA }, { 0x0BAE, 0x0BB5 }, { 0x0BB7, 0x0BB9 }, { 0x0BBE, 0x0BC2 },
+    { 0x0BC6, 0x0BC8 }, { 0x0BCA, 0x0BCD }, { 0x0BE7, 0x0BEF }, { 0x0C01, 0x0C03 },
+    { 0x0C05, 0x0C0C }, { 0x0C0E, 0x0C10 }, { 0x0C12, 0x0C28 }, { 0x0C2A, 0x0C33 },
+    { 0x0C35, 0x0C39 }, { 0x0C3E, 0x0C44 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D },
+    { 0x0C60, 0x0C61 }, { 0x0C66, 0x0C6F }, { 0x0C82, 0x0C83 }, { 0x0C85, 0x0C8C },
+    { 0x0C8E, 0x0C90 }, { 0x0C92, 0x0CA8 }, { 0x0CAA, 0x0CB3 }, { 0x0CB5, 0x0CB9 },
+    { 0x0CBE, 0x0CC4 }, { 0x0CC6, 0x0CC8 }, { 0x0CCA, 0x0CCD }, { 0x0CDE, 0x0CDE },
+    { 0x0CE0, 0x0CE1 }, { 0x0CE6, 0x0CEF }, { 0x0D02, 0x0D03 }, { 0x0D05, 0x0D0C },
+    { 0x0D0E, 0x0D10 }, { 0x0D12, 0x0D28 }, { 0x0D2A, 0x0D39 }, { 0x0D3E, 0x0D43 },
+    { 0x0D46, 0x0D48 }, { 0x0D4A, 0x0D4D }, { 0x0D60, 0x0D61 }, { 0x0D66, 0x0D6F },
+    { 0x0E01, 0x0E3A }, { 0x0E40, 0x0E5B }, { 0x0E81, 0x0E82 },
+    { 0x0E84, 0x0E84 }, { 0x0E87, 0x0E88 }, { 0x0E8A, 0x0E8A }, { 0x0E8D, 0x0E8D },
+    { 0x0E94, 0x0E97 }, { 0x0E99, 0x0E9F }, { 0x0EA1, 0x0EA3 }, { 0x0EA5, 0x0EA5 },
+    { 0x0EA7, 0x0EA7 }, { 0x0EAA, 0x0EAB }, { 0x0EAD, 0x0EAE }, { 0x0EB0, 0x0EB9 },
+    { 0x0EBB, 0x0EBD }, { 0x0EC0, 0x0EC4 }, { 0x0EC6, 0x0EC6 }, { 0x0EC8, 0x0ECD },
+    { 0x0ED0, 0x0ED9 }, { 0x0EDC, 0x0EDD }, { 0x0F00, 0x0F00 }, { 0x0F18, 0x0F19 },
+    { 0x0F20, 0x0F33 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 },
+    { 0x0F3E, 0x0F47 }, { 0x0F49, 0x0F69 }, { 0x0F71, 0x0F84 }, { 0x0F86, 0x0F8B },
+    { 0x0F90, 0x0F95 }, { 0x0F97, 0x0F97 }, { 0x0F99, 0x0FAD }, { 0x0FB1, 0x0FB7 },
+    { 0x0FB9, 0x0FB9 }, { 0x10A0, 0x10C5 }, { 0x10D0, 0x10F6 }, { 0x1E00, 0x1E9B },
+    { 0x1EA0, 0x1EF9 }, { 0x1F00, 0x1F15 }, { 0x1F18, 0x1F1D }, { 0x1F20, 0x1F45 },
+    { 0x1F48, 0x1F4D }, { 0x1F50, 0x1F57 }, { 0x1F59, 0x1F59 }, { 0x1F5B, 0x1F5B },
+    { 0x1F5D, 0x1F5D }, { 0x1F5F, 0x1F7D }, { 0x1F80, 0x1FB4 }, { 0x1FB6, 0x1FBC },
+    { 0x1FBE, 0x1FBE }, { 0x1FC2, 0x1FC4 }, { 0x1FC6, 0x1FCC }, { 0x1FD0, 0x1FD3 },
+    { 0x1FD6, 0x1FDB }, { 0x1FE0, 0x1FEC }, { 0x1FF2, 0x1FF4 }, { 0x1FF6, 0x1FFC },
+    { 0x203F, 0x2040 }, { 0x207F, 0x207F }, { 0x2102, 0x2102 }, { 0x2107, 0x2107 },
+    { 0x210A, 0x2113 }, { 0x2115, 0x2115 }, { 0x2118, 0x211D }, { 0x2124, 0x2124 },
+    { 0x2126, 0x2126 }, { 0x2128, 0x2128 }, { 0x212A, 0x2131 }, { 0x2133, 0x2138 },
+    { 0x2160, 0x2182 }, { 0x3005, 0x3007 }, { 0x3021, 0x3029 }, { 0x3041, 0x3093 },
+    { 0x309B, 0x309C }, { 0x30A1, 0x30F6 }, { 0x30FB, 0x30FC }, { 0x3105, 0x312C },
+    { 0x4E00, 0x9FA5 }, { 0xAC00, 0xD7A3 },
+};
+
+char const *const UTF8_DECODE_OK = NULL;
+extern char const UTF8_DECODE_OUTSIDE_CODE_SPACE[];
+extern char const UTF8_DECODE_TRUNCATED_SEQUENCE[];
+extern char const UTF8_DECODE_OVERLONG[];
+extern char const UTF8_DECODE_INVALID_TRAILER[];
+extern char const UTF8_DECODE_INVALID_CODE_POINT[];
+
+char const *const UTF16_DECODE_OK = NULL;
+extern char const UTF16_DECODE_TRUNCATED_SEQUENCE[];
+extern char const UTF16_DECODE_INVALID_SURROGATE[];
+extern char const UTF16_DECODE_UNPAIRED_SURROGATE[];
+extern char const UTF16_DECODE_INVALID_CODE_POINT[];
+
+/// \return true if \a c is a valid, non-private UTF-32 code point
+bool utf_isValidDchar(dchar_t c);
+
+bool isUniAlpha(dchar_t c);
+
+int utf_codeLengthChar(dchar_t c);
+int utf_codeLengthWchar(dchar_t c);
+int utf_codeLength(int sz, dchar_t c);
+
+void utf_encodeChar(utf8_t *s, dchar_t c);
+void utf_encodeWchar(utf16_t *s, dchar_t c);
+void utf_encode(int sz, void *s, dchar_t c);
+
+const char *utf_decodeChar(utf8_t const *s, size_t len, size_t *pidx, dchar_t *presult);
+const char *utf_decodeWchar(utf16_t const *s, size_t len, size_t *pidx, dchar_t *presult);
+
+#endif  // DMD_UTF_H
diff --git a/gcc/d/dfrontend/utils.c b/gcc/d/dfrontend/utils.c
new file mode 100644
index 00000000000..10f800554ba
--- /dev/null
+++ b/gcc/d/dfrontend/utils.c
@@ -0,0 +1,122 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2015 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+#include <string.h>
+#include "errors.h"
+#include "globals.h"
+#include "file.h"
+#include "filename.h"
+#include "outbuffer.h"
+
+/**
+ * Normalize path by turning forward slashes into backslashes
+ *
+ * Params:
+ *   src = Source path, using unix-style ('/') path separators
+ *
+ * Returns:
+ *   A newly-allocated string with '/' turned into backslashes
+ */
+const char * toWinPath(const char *src)
+{
+    if (src == NULL)
+        return NULL;
+
+    char *result = strdup(src);
+    char *p = result;
+    while (*p != '\0')
+    {
+        if (*p == '/')
+            *p = '\\';
+        p++;
+    }
+    return result;
+}
+
+/**
+ * Reads a file, terminate the program on error
+ *
+ * Params:
+ *   loc = The line number information from where the call originates
+ *   f = a `ddmd.root.file.File` handle to read
+ */
+void readFile(Loc loc, File *f)
+{
+    if (f->read())
+    {
+        error(loc, "Error reading file '%s'", f->name->toChars());
+        fatal();
+    }
+}
+
+/**
+ * Writes a file, terminate the program on error
+ *
+ * Params:
+ *   loc = The line number information from where the call originates
+ *   f = a `ddmd.root.file.File` handle to write
+ */
+void writeFile(Loc loc, File *f)
+{
+    if (f->write())
+    {
+        error(loc, "Error writing file '%s'", f->name->toChars());
+        fatal();
+    }
+}
+
+/**
+ * Ensure the root path (the path minus the name) of the provided path
+ * exists, and terminate the process if it doesn't.
+ *
+ * Params:
+ *   loc = The line number information from where the call originates
+ *   name = a path to check (the name is stripped)
+ */
+void ensurePathToNameExists(Loc loc, const char *name)
+{
+    const char *pt = FileName::path(name);
+    if (*pt)
+    {
+        if (FileName::ensurePathExists(pt))
+        {
+            error(loc, "cannot create directory %s", pt);
+            fatal();
+        }
+    }
+    FileName::free(pt);
+}
+
+/**
+ * Takes a path, and escapes '(', ')' and backslashes
+ *
+ * Params:
+ *   buf = Buffer to write the escaped path to
+ *   fname = Path to escape
+ */
+void escapePath(OutBuffer *buf, const char *fname)
+{
+    while (1)
+    {
+        switch (*fname)
+        {
+            case 0:
+                return;
+            case '(':
+            case ')':
+            case '\\':
+                buf->writeByte('\\');
+            default:
+                buf->writeByte(*fname);
+                break;
+        }
+        fname++;
+    }
+}
diff --git a/gcc/d/dfrontend/version.h b/gcc/d/dfrontend/version.h
new file mode 100644
index 00000000000..fc54b1da216
--- /dev/null
+++ b/gcc/d/dfrontend/version.h
@@ -0,0 +1,53 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 1999-2016 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/version.h
+ */
+
+#ifndef DMD_VERSION_H
+#define DMD_VERSION_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+
+class DebugSymbol : public Dsymbol
+{
+public:
+    unsigned level;
+
+    DebugSymbol(Loc loc, Identifier *ident);
+    DebugSymbol(Loc loc, unsigned level);
+    Dsymbol *syntaxCopy(Dsymbol *);
+
+    const char *toChars();
+    void addMember(Scope *sc, ScopeDsymbol *sds);
+    void semantic(Scope *sc);
+    const char *kind();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+class VersionSymbol : public Dsymbol
+{
+public:
+    unsigned level;
+
+    VersionSymbol(Loc loc, Identifier *ident);
+    VersionSymbol(Loc loc, unsigned level);
+    Dsymbol *syntaxCopy(Dsymbol *);
+
+    const char *toChars();
+    void addMember(Scope *sc, ScopeDsymbol *sds);
+    void semantic(Scope *sc);
+    const char *kind();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
+#endif /* DMD_VERSION_H */
diff --git a/gcc/d/dfrontend/visitor.h b/gcc/d/dfrontend/visitor.h
new file mode 100644
index 00000000000..e7d246cad99
--- /dev/null
+++ b/gcc/d/dfrontend/visitor.h
@@ -0,0 +1,605 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (c) 2013-2014 by Digital Mars
+ * All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/visitor.h
+ */
+
+#ifndef DMD_VISITOR_H
+#define DMD_VISITOR_H
+
+#include <assert.h>
+
+class Statement;
+class ErrorStatement;
+class PeelStatement;
+class ExpStatement;
+class DtorExpStatement;
+class CompileStatement;
+class CompoundStatement;
+class CompoundDeclarationStatement;
+class UnrolledLoopStatement;
+class ScopeStatement;
+class ForwardingStatement;
+class WhileStatement;
+class DoStatement;
+class ForStatement;
+class ForeachStatement;
+class ForeachRangeStatement;
+class StaticForeachStatement;
+class IfStatement;
+class ConditionalStatement;
+class PragmaStatement;
+class StaticAssertStatement;
+class SwitchStatement;
+class CaseStatement;
+class CaseRangeStatement;
+class DefaultStatement;
+class GotoDefaultStatement;
+class GotoCaseStatement;
+class SwitchErrorStatement;
+class ReturnStatement;
+class BreakStatement;
+class ContinueStatement;
+class SynchronizedStatement;
+class WithStatement;
+class TryCatchStatement;
+class TryFinallyStatement;
+class OnScopeStatement;
+class ThrowStatement;
+class DebugStatement;
+class GotoStatement;
+class LabelStatement;
+class AsmStatement;
+class CompoundAsmStatement;
+#ifdef IN_GCC
+class ExtAsmStatement;
+#endif
+class ImportStatement;
+
+class Type;
+class TypeError;
+class TypeNext;
+class TypeBasic;
+class TypeVector;
+class TypeArray;
+class TypeSArray;
+class TypeDArray;
+class TypeAArray;
+class TypePointer;
+class TypeReference;
+class TypeFunction;
+class TypeDelegate;
+class TypeQualified;
+class TypeIdentifier;
+class TypeInstance;
+class TypeTypeof;
+class TypeReturn;
+class TypeStruct;
+class TypeEnum;
+class TypeClass;
+class TypeTuple;
+class TypeSlice;
+class TypeNull;
+
+class Dsymbol;
+
+class StaticAssert;
+class DebugSymbol;
+class VersionSymbol;
+class EnumMember;
+class Import;
+class OverloadSet;
+class LabelDsymbol;
+class AliasThis;
+
+class AttribDeclaration;
+class StorageClassDeclaration;
+class DeprecatedDeclaration;
+class LinkDeclaration;
+class CPPMangleDeclaration;
+class ProtDeclaration;
+class AlignDeclaration;
+class AnonDeclaration;
+class PragmaDeclaration;
+class ConditionalDeclaration;
+class StaticIfDeclaration;
+class CompileDeclaration;
+class StaticForeachDeclaration;
+class UserAttributeDeclaration;
+
+class ScopeDsymbol;
+class TemplateDeclaration;
+class TemplateInstance;
+class TemplateMixin;
+class EnumDeclaration;
+class Package;
+class Module;
+class WithScopeSymbol;
+class ArrayScopeSymbol;
+class Nspace;
+
+class AggregateDeclaration;
+class StructDeclaration;
+class UnionDeclaration;
+class ClassDeclaration;
+class InterfaceDeclaration;
+
+class Declaration;
+class TupleDeclaration;
+class AliasDeclaration;
+class OverDeclaration;
+class VarDeclaration;
+class SymbolDeclaration;
+class ThisDeclaration;
+
+class TypeInfoDeclaration;
+class TypeInfoStructDeclaration;
+class TypeInfoClassDeclaration;
+class TypeInfoInterfaceDeclaration;
+class TypeInfoPointerDeclaration;
+class TypeInfoArrayDeclaration;
+class TypeInfoStaticArrayDeclaration;
+class TypeInfoAssociativeArrayDeclaration;
+class TypeInfoEnumDeclaration;
+class TypeInfoFunctionDeclaration;
+class TypeInfoDelegateDeclaration;
+class TypeInfoTupleDeclaration;
+class TypeInfoConstDeclaration;
+class TypeInfoInvariantDeclaration;
+class TypeInfoSharedDeclaration;
+class TypeInfoWildDeclaration;
+class TypeInfoVectorDeclaration;
+
+class FuncDeclaration;
+class FuncAliasDeclaration;
+class FuncLiteralDeclaration;
+class CtorDeclaration;
+class PostBlitDeclaration;
+class DtorDeclaration;
+class StaticCtorDeclaration;
+class SharedStaticCtorDeclaration;
+class StaticDtorDeclaration;
+class SharedStaticDtorDeclaration;
+class InvariantDeclaration;
+class UnitTestDeclaration;
+class NewDeclaration;
+class DeleteDeclaration;
+
+class Initializer;
+class VoidInitializer;
+class ErrorInitializer;
+class StructInitializer;
+class ArrayInitializer;
+class ExpInitializer;
+
+class Expression;
+class IntegerExp;
+class ErrorExp;
+class RealExp;
+class ComplexExp;
+class IdentifierExp;
+class DollarExp;
+class DsymbolExp;
+class ThisExp;
+class SuperExp;
+class NullExp;
+class StringExp;
+class TupleExp;
+class ArrayLiteralExp;
+class AssocArrayLiteralExp;
+class StructLiteralExp;
+class TypeExp;
+class ScopeExp;
+class TemplateExp;
+class NewExp;
+class NewAnonClassExp;
+class SymbolExp;
+class SymOffExp;
+class VarExp;
+class OverExp;
+class FuncExp;
+class DeclarationExp;
+class TypeidExp;
+class TraitsExp;
+class HaltExp;
+class IsExp;
+class UnaExp;
+class BinExp;
+class BinAssignExp;
+class CompileExp;
+class ImportExp;
+class AssertExp;
+class DotIdExp;
+class DotTemplateExp;
+class DotVarExp;
+class DotTemplateInstanceExp;
+class DelegateExp;
+class DotTypeExp;
+class CallExp;
+class AddrExp;
+class PtrExp;
+class NegExp;
+class UAddExp;
+class ComExp;
+class NotExp;
+class DeleteExp;
+class CastExp;
+class VectorExp;
+class SliceExp;
+class ArrayLengthExp;
+class IntervalExp;
+class DelegatePtrExp;
+class DelegateFuncptrExp;
+class ArrayExp;
+class DotExp;
+class CommaExp;
+class IndexExp;
+class PostExp;
+class PreExp;
+class AssignExp;
+class ConstructExp;
+class BlitExp;
+class AddAssignExp;
+class MinAssignExp;
+class MulAssignExp;
+class DivAssignExp;
+class ModAssignExp;
+class AndAssignExp;
+class OrAssignExp;
+class XorAssignExp;
+class PowAssignExp;
+class ShlAssignExp;
+class ShrAssignExp;
+class UshrAssignExp;
+class CatAssignExp;
+class AddExp;
+class MinExp;
+class CatExp;
+class MulExp;
+class DivExp;
+class ModExp;
+class PowExp;
+class ShlExp;
+class ShrExp;
+class UshrExp;
+class AndExp;
+class OrExp;
+class XorExp;
+class OrOrExp;
+class AndAndExp;
+class CmpExp;
+class InExp;
+class RemoveExp;
+class EqualExp;
+class IdentityExp;
+class CondExp;
+class DefaultInitExp;
+class FileInitExp;
+class LineInitExp;
+class ModuleInitExp;
+class FuncInitExp;
+class PrettyFuncInitExp;
+class ClassReferenceExp;
+class VoidInitExp;
+class ThrownExceptionExp;
+
+class TemplateParameter;
+class TemplateTypeParameter;
+class TemplateThisParameter;
+class TemplateValueParameter;
+class TemplateAliasParameter;
+class TemplateTupleParameter;
+
+class Condition;
+class DVCondition;
+class DebugCondition;
+class VersionCondition;
+class StaticIfCondition;
+
+class Parameter;
+
+class Visitor
+{
+public:
+    virtual void visit(Statement *) { assert(0); }
+    virtual void visit(ErrorStatement *s) { visit((Statement *)s); }
+    virtual void visit(PeelStatement *s) { visit((Statement *)s); }
+    virtual void visit(ExpStatement *s) { visit((Statement *)s); }
+    virtual void visit(DtorExpStatement *s) { visit((ExpStatement *)s); }
+    virtual void visit(CompileStatement *s) { visit((Statement *)s); }
+    virtual void visit(CompoundStatement *s) { visit((Statement *)s); }
+    virtual void visit(CompoundDeclarationStatement *s) { visit((CompoundStatement *)s); }
+    virtual void visit(UnrolledLoopStatement *s) { visit((Statement *)s); }
+    virtual void visit(ScopeStatement *s) { visit((Statement *)s); }
+    virtual void visit(ForwardingStatement *s) { visit((Statement *)s); }
+    virtual void visit(WhileStatement *s) { visit((Statement *)s); }
+    virtual void visit(DoStatement *s) { visit((Statement *)s); }
+    virtual void visit(ForStatement *s) { visit((Statement *)s); }
+    virtual void visit(ForeachStatement *s) { visit((Statement *)s); }
+    virtual void visit(ForeachRangeStatement *s) { visit((Statement *)s); }
+    virtual void visit(StaticForeachStatement *s) { visit((Statement *)s); }
+    virtual void visit(IfStatement *s) { visit((Statement *)s); }
+    virtual void visit(ConditionalStatement *s) { visit((Statement *)s); }
+    virtual void visit(PragmaStatement *s) { visit((Statement *)s); }
+    virtual void visit(StaticAssertStatement *s) { visit((Statement *)s); }
+    virtual void visit(SwitchStatement *s) { visit((Statement *)s); }
+    virtual void visit(CaseStatement *s) { visit((Statement *)s); }
+    virtual void visit(CaseRangeStatement *s) { visit((Statement *)s); }
+    virtual void visit(DefaultStatement *s) { visit((Statement *)s); }
+    virtual void visit(GotoDefaultStatement *s) { visit((Statement *)s); }
+    virtual void visit(GotoCaseStatement *s) { visit((Statement *)s); }
+    virtual void visit(SwitchErrorStatement *s) { visit((Statement *)s); }
+    virtual void visit(ReturnStatement *s) { visit((Statement *)s); }
+    virtual void visit(BreakStatement *s) { visit((Statement *)s); }
+    virtual void visit(ContinueStatement *s) { visit((Statement *)s); }
+    virtual void visit(SynchronizedStatement *s) { visit((Statement *)s); }
+    virtual void visit(WithStatement *s) { visit((Statement *)s); }
+    virtual void visit(TryCatchStatement *s) { visit((Statement *)s); }
+    virtual void visit(TryFinallyStatement *s) { visit((Statement *)s); }
+    virtual void visit(OnScopeStatement *s) { visit((Statement *)s); }
+    virtual void visit(ThrowStatement *s) { visit((Statement *)s); }
+    virtual void visit(DebugStatement *s) { visit((Statement *)s); }
+    virtual void visit(GotoStatement *s) { visit((Statement *)s); }
+    virtual void visit(LabelStatement *s) { visit((Statement *)s); }
+    virtual void visit(AsmStatement *s) { visit((Statement *)s); }
+    virtual void visit(CompoundAsmStatement *s) { visit((CompoundStatement *)s); }
+#ifdef IN_GCC
+    virtual void visit(ExtAsmStatement *s) { visit((Statement *)s); }
+#endif
+    virtual void visit(ImportStatement *s) { visit((Statement *)s); }
+
+    virtual void visit(Type *) { assert(0); }
+    virtual void visit(TypeError *t) { visit((Type *)t); }
+    virtual void visit(TypeNext *t) { visit((Type *)t); }
+    virtual void visit(TypeBasic *t) { visit((Type *)t); }
+    virtual void visit(TypeVector *t) { visit((Type *)t); }
+    virtual void visit(TypeArray *t) { visit((TypeNext *)t); }
+    virtual void visit(TypeSArray *t) { visit((TypeArray *)t); }
+    virtual void visit(TypeDArray *t) { visit((TypeArray *)t); }
+    virtual void visit(TypeAArray *t) { visit((TypeArray *)t); }
+    virtual void visit(TypePointer *t) { visit((TypeNext *)t); }
+    virtual void visit(TypeReference *t) { visit((TypeNext *)t); }
+    virtual void visit(TypeFunction *t) { visit((TypeNext *)t); }
+    virtual void visit(TypeDelegate *t) { visit((TypeNext *)t); }
+    virtual void visit(TypeQualified *t) { visit((Type *)t); }
+    virtual void visit(TypeIdentifier *t) { visit((TypeQualified *)t); }
+    virtual void visit(TypeInstance *t) { visit((TypeQualified *)t); }
+    virtual void visit(TypeTypeof *t) { visit((TypeQualified *)t); }
+    virtual void visit(TypeReturn *t) { visit((TypeQualified *)t); }
+    virtual void visit(TypeStruct *t) { visit((Type *)t); }
+    virtual void visit(TypeEnum *t) { visit((Type *)t); }
+    virtual void visit(TypeClass *t) { visit((Type *)t); }
+    virtual void visit(TypeTuple *t) { visit((Type *)t); }
+    virtual void visit(TypeSlice *t) { visit((TypeNext *)t); }
+    virtual void visit(TypeNull *t) { visit((Type *)t); }
+
+    virtual void visit(Dsymbol *) { assert(0); }
+
+    virtual void visit(StaticAssert *s) { visit((Dsymbol *)s); }
+    virtual void visit(DebugSymbol *s) { visit((Dsymbol *)s); }
+    virtual void visit(VersionSymbol *s) { visit((Dsymbol *)s); }
+    virtual void visit(EnumMember *s) { visit((VarDeclaration *)s); }
+    virtual void visit(Import *s) { visit((Dsymbol *)s); }
+    virtual void visit(OverloadSet *s) { visit((Dsymbol *)s); }
+    virtual void visit(LabelDsymbol *s) { visit((Dsymbol *)s); }
+    virtual void visit(AliasThis *s) { visit((Dsymbol *)s); }
+
+    virtual void visit(AttribDeclaration *s) { visit((Dsymbol *)s); }
+    virtual void visit(StorageClassDeclaration *s) { visit((AttribDeclaration *)s); }
+    virtual void visit(DeprecatedDeclaration *s) { visit((StorageClassDeclaration *)s); }
+    virtual void visit(LinkDeclaration *s) { visit((AttribDeclaration *)s); }
+    virtual void visit(CPPMangleDeclaration *s) { visit((AttribDeclaration *)s); }
+    virtual void visit(ProtDeclaration *s) { visit((AttribDeclaration *)s); }
+    virtual void visit(AlignDeclaration *s) { visit((AttribDeclaration *)s); }
+    virtual void visit(AnonDeclaration *s) { visit((AttribDeclaration *)s); }
+    virtual void visit(PragmaDeclaration *s) { visit((AttribDeclaration *)s); }
+    virtual void visit(ConditionalDeclaration *s) { visit((AttribDeclaration *)s); }
+    virtual void visit(StaticIfDeclaration *s) { visit((ConditionalDeclaration *)s); }
+    virtual void visit(CompileDeclaration *s) { visit((AttribDeclaration *)s); }
+    virtual void visit(StaticForeachDeclaration *s) { visit((AttribDeclaration *)s); }
+    virtual void visit(UserAttributeDeclaration *s) { visit((AttribDeclaration *)s); }
+
+    virtual void visit(ScopeDsymbol *s) { visit((Dsymbol *)s); }
+    virtual void visit(TemplateDeclaration *s) { visit((ScopeDsymbol *)s); }
+    virtual void visit(TemplateInstance *s) { visit((ScopeDsymbol *)s); }
+    virtual void visit(TemplateMixin *s) { visit((TemplateInstance *)s); }
+    virtual void visit(EnumDeclaration *s) { visit((ScopeDsymbol *)s); }
+    virtual void visit(Package *s) { visit((ScopeDsymbol *)s); }
+    virtual void visit(Module *s) { visit((Package *)s); }
+    virtual void visit(WithScopeSymbol *s) { visit((ScopeDsymbol *)s); }
+    virtual void visit(ArrayScopeSymbol *s) { visit((ScopeDsymbol *)s); }
+    virtual void visit(Nspace *s) { visit((ScopeDsymbol *)s); }
+
+    virtual void visit(AggregateDeclaration *s) { visit((ScopeDsymbol *)s); }
+    virtual void visit(StructDeclaration *s) { visit((AggregateDeclaration *)s); }
+    virtual void visit(UnionDeclaration *s) { visit((StructDeclaration *)s); }
+    virtual void visit(ClassDeclaration *s) { visit((AggregateDeclaration *)s); }
+    virtual void visit(InterfaceDeclaration *s) { visit((ClassDeclaration *)s); }
+
+    virtual void visit(Declaration *s) { visit((Dsymbol *)s); }
+    virtual void visit(TupleDeclaration *s) { visit((Declaration *)s); }
+    virtual void visit(AliasDeclaration *s) { visit((Declaration *)s); }
+    virtual void visit(OverDeclaration *s) { visit((Declaration *)s); }
+    virtual void visit(VarDeclaration *s) { visit((Declaration *)s); }
+    virtual void visit(SymbolDeclaration *s) { visit((Declaration *)s); }
+    virtual void visit(ThisDeclaration *s) { visit((VarDeclaration *)s); }
+
+    virtual void visit(TypeInfoDeclaration *s) { visit((VarDeclaration *)s); }
+    virtual void visit(TypeInfoStructDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoClassDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoInterfaceDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoPointerDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoArrayDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoStaticArrayDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoAssociativeArrayDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoEnumDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoFunctionDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoDelegateDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoTupleDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoConstDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoInvariantDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoSharedDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoWildDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+    virtual void visit(TypeInfoVectorDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+
+    virtual void visit(FuncDeclaration *s) { visit((Declaration *)s); }
+    virtual void visit(FuncAliasDeclaration *s) { visit((FuncDeclaration *)s); }
+    virtual void visit(FuncLiteralDeclaration *s) { visit((FuncDeclaration *)s); }
+    virtual void visit(CtorDeclaration *s) { visit((FuncDeclaration *)s); }
+    virtual void visit(PostBlitDeclaration *s) { visit((FuncDeclaration *)s); }
+    virtual void visit(DtorDeclaration *s) { visit((FuncDeclaration *)s); }
+    virtual void visit(StaticCtorDeclaration *s) { visit((FuncDeclaration *)s); }
+    virtual void visit(SharedStaticCtorDeclaration *s) { visit((StaticCtorDeclaration *)s); }
+    virtual void visit(StaticDtorDeclaration *s) { visit((FuncDeclaration *)s); }
+    virtual void visit(SharedStaticDtorDeclaration *s) { visit((StaticDtorDeclaration *)s); }
+    virtual void visit(InvariantDeclaration *s) { visit((FuncDeclaration *)s); }
+    virtual void visit(UnitTestDeclaration *s) { visit((FuncDeclaration *)s); }
+    virtual void visit(NewDeclaration *s) { visit((FuncDeclaration *)s); }
+    virtual void visit(DeleteDeclaration *s) { visit((FuncDeclaration *)s); }
+
+    virtual void visit(Initializer *) { assert(0); }
+    virtual void visit(VoidInitializer *i) { visit((Initializer *)i); }
+    virtual void visit(ErrorInitializer *i) { visit((Initializer *)i); }
+    virtual void visit(StructInitializer *i) { visit((Initializer *)i); }
+    virtual void visit(ArrayInitializer *i) { visit((Initializer *)i); }
+    virtual void visit(ExpInitializer *i) { visit((Initializer *)i); }
+
+    virtual void visit(Expression *) { assert(0); }
+    virtual void visit(IntegerExp *e) { visit((Expression *)e); }
+    virtual void visit(ErrorExp *e) { visit((Expression *)e); }
+    virtual void visit(RealExp *e) { visit((Expression *)e); }
+    virtual void visit(ComplexExp *e) { visit((Expression *)e); }
+    virtual void visit(IdentifierExp *e) { visit((Expression *)e); }
+    virtual void visit(DollarExp *e) { visit((IdentifierExp *)e); }
+    virtual void visit(DsymbolExp *e) { visit((Expression *)e); }
+    virtual void visit(ThisExp *e) { visit((Expression *)e); }
+    virtual void visit(SuperExp *e) { visit((ThisExp *)e); }
+    virtual void visit(NullExp *e) { visit((Expression *)e); }
+    virtual void visit(StringExp *e) { visit((Expression *)e); }
+    virtual void visit(TupleExp *e) { visit((Expression *)e); }
+    virtual void visit(ArrayLiteralExp *e) { visit((Expression *)e); }
+    virtual void visit(AssocArrayLiteralExp *e) { visit((Expression *)e); }
+    virtual void visit(StructLiteralExp *e) { visit((Expression *)e); }
+    virtual void visit(TypeExp *e) { visit((Expression *)e); }
+    virtual void visit(ScopeExp *e) { visit((Expression *)e); }
+    virtual void visit(TemplateExp *e) { visit((Expression *)e); }
+    virtual void visit(NewExp *e) { visit((Expression *)e); }
+    virtual void visit(NewAnonClassExp *e) { visit((Expression *)e); }
+    virtual void visit(SymbolExp *e) { visit((Expression *)e); }
+    virtual void visit(SymOffExp *e) { visit((SymbolExp *)e); }
+    virtual void visit(VarExp *e) { visit((SymbolExp *)e); }
+    virtual void visit(OverExp *e) { visit((Expression *)e); }
+    virtual void visit(FuncExp *e) { visit((Expression *)e); }
+    virtual void visit(DeclarationExp *e) { visit((Expression *)e); }
+    virtual void visit(TypeidExp *e) { visit((Expression *)e); }
+    virtual void visit(TraitsExp *e) { visit((Expression *)e); }
+    virtual void visit(HaltExp *e) { visit((Expression *)e); }
+    virtual void visit(IsExp *e) { visit((Expression *)e); }
+    virtual void visit(UnaExp *e) { visit((Expression *)e); }
+    virtual void visit(BinExp *e) { visit((Expression *)e); }
+    virtual void visit(BinAssignExp *e) { visit((BinExp *)e); }
+    virtual void visit(CompileExp *e) { visit((UnaExp *)e); }
+    virtual void visit(ImportExp *e) { visit((UnaExp *)e); }
+    virtual void visit(AssertExp *e) { visit((UnaExp *)e); }
+    virtual void visit(DotIdExp *e) { visit((UnaExp *)e); }
+    virtual void visit(DotTemplateExp *e) { visit((UnaExp *)e); }
+    virtual void visit(DotVarExp *e) { visit((UnaExp *)e); }
+    virtual void visit(DotTemplateInstanceExp *e) { visit((UnaExp *)e); }
+    virtual void visit(DelegateExp *e) { visit((UnaExp *)e); }
+    virtual void visit(DotTypeExp *e) { visit((UnaExp *)e); }
+    virtual void visit(CallExp *e) { visit((UnaExp *)e); }
+    virtual void visit(AddrExp *e) { visit((UnaExp *)e); }
+    virtual void visit(PtrExp *e) { visit((UnaExp *)e); }
+    virtual void visit(NegExp *e) { visit((UnaExp *)e); }
+    virtual void visit(UAddExp *e) { visit((UnaExp *)e); }
+    virtual void visit(ComExp *e) { visit((UnaExp *)e); }
+    virtual void visit(NotExp *e) { visit((UnaExp *)e); }
+    virtual void visit(DeleteExp *e) { visit((UnaExp *)e); }
+    virtual void visit(CastExp *e) { visit((UnaExp *)e); }
+    virtual void visit(VectorExp *e) { visit((UnaExp *)e); }
+    virtual void visit(SliceExp *e) { visit((UnaExp *)e); }
+    virtual void visit(ArrayLengthExp *e) { visit((UnaExp *)e); }
+    virtual void visit(IntervalExp *e) { visit((Expression *)e); }
+    virtual void visit(DelegatePtrExp *e) { visit((UnaExp *)e); }
+    virtual void visit(DelegateFuncptrExp *e) { visit((UnaExp *)e); }
+    virtual void visit(ArrayExp *e) { visit((UnaExp *)e); }
+    virtual void visit(DotExp *e) { visit((BinExp *)e); }
+    virtual void visit(CommaExp *e) { visit((BinExp *)e); }
+    virtual void visit(IndexExp *e) { visit((BinExp *)e); }
+    virtual void visit(PostExp *e) { visit((BinExp *)e); }
+    virtual void visit(PreExp *e) { visit((UnaExp *)e); }
+    virtual void visit(AssignExp *e) { visit((BinExp *)e); }
+    virtual void visit(ConstructExp *e) { visit((AssignExp *)e); }
+    virtual void visit(BlitExp *e) { visit((AssignExp *)e); }
+    virtual void visit(AddAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(MinAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(MulAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(DivAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(ModAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(AndAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(OrAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(XorAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(PowAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(ShlAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(ShrAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(UshrAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(CatAssignExp *e) { visit((BinAssignExp *)e); }
+    virtual void visit(AddExp *e) { visit((BinExp *)e); }
+    virtual void visit(MinExp *e) { visit((BinExp *)e); }
+    virtual void visit(CatExp *e) { visit((BinExp *)e); }
+    virtual void visit(MulExp *e) { visit((BinExp *)e); }
+    virtual void visit(DivExp *e) { visit((BinExp *)e); }
+    virtual void visit(ModExp *e) { visit((BinExp *)e); }
+    virtual void visit(PowExp *e) { visit((BinExp *)e); }
+    virtual void visit(ShlExp *e) { visit((BinExp *)e); }
+    virtual void visit(ShrExp *e) { visit((BinExp *)e); }
+    virtual void visit(UshrExp *e) { visit((BinExp *)e); }
+    virtual void visit(AndExp *e) { visit((BinExp *)e); }
+    virtual void visit(OrExp *e) { visit((BinExp *)e); }
+    virtual void visit(XorExp *e) { visit((BinExp *)e); }
+    virtual void visit(OrOrExp *e) { visit((BinExp *)e); }
+    virtual void visit(AndAndExp *e) { visit((BinExp *)e); }
+    virtual void visit(CmpExp *e) { visit((BinExp *)e); }
+    virtual void visit(InExp *e) { visit((BinExp *)e); }
+    virtual void visit(RemoveExp *e) { visit((BinExp *)e); }
+    virtual void visit(EqualExp *e) { visit((BinExp *)e); }
+    virtual void visit(IdentityExp *e) { visit((BinExp *)e); }
+    virtual void visit(CondExp *e) { visit((BinExp *)e); }
+    virtual void visit(DefaultInitExp *e) { visit((Expression *)e); }
+    virtual void visit(FileInitExp *e) { visit((DefaultInitExp *)e); }
+    virtual void visit(LineInitExp *e) { visit((DefaultInitExp *)e); }
+    virtual void visit(ModuleInitExp *e) { visit((DefaultInitExp *)e); }
+    virtual void visit(FuncInitExp *e) { visit((DefaultInitExp *)e); }
+    virtual void visit(PrettyFuncInitExp *e) { visit((DefaultInitExp *)e); }
+    virtual void visit(ClassReferenceExp *e) { visit((Expression *)e); }
+    virtual void visit(VoidInitExp *e) { visit((Expression *)e); }
+    virtual void visit(ThrownExceptionExp *e) { visit((Expression *)e); }
+
+    virtual void visit(TemplateParameter *) { assert(0); }
+    virtual void visit(TemplateTypeParameter *tp) { visit((TemplateParameter *)tp); }
+    virtual void visit(TemplateThisParameter *tp) { visit((TemplateTypeParameter *)tp); }
+    virtual void visit(TemplateValueParameter *tp) { visit((TemplateParameter *)tp); }
+    virtual void visit(TemplateAliasParameter *tp) { visit((TemplateParameter *)tp); }
+    virtual void visit(TemplateTupleParameter *tp) { visit((TemplateParameter *)tp); }
+
+    virtual void visit(Condition *) { assert(0); }
+    virtual void visit(DVCondition *c) { visit((Condition *)c); }
+    virtual void visit(DebugCondition *c) { visit((DVCondition *)c); }
+    virtual void visit(VersionCondition *c) { visit((DVCondition *)c); }
+    virtual void visit(StaticIfCondition *c) { visit((Condition *)c); }
+
+    virtual void visit(Parameter *) { assert(0); }
+};
+
+class StoppableVisitor : public Visitor
+{
+public:
+    bool stop;
+    StoppableVisitor() : stop(false) {}
+};
+
+#endif /* DMD_VISITOR_H */
