diff gcc/d/dmd/initsem.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/d/dmd/initsem.c	Thu Feb 13 11:34:05 2020 +0900
@@ -0,0 +1,917 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2019 by The D Language Foundation, 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 "root/checkedint.h"
+#include "mars.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);
+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 k = 0; k < nfields; k++)
+                {
+                    VarDeclaration *v2 = sd->fields[k];
+                    if (vd->isOverlappedWith(v2) && (*elements)[k])
+                    {
+                        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] = doCopyOrMove(sc, 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;
+                /* fall through */
+
+            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", (ulonglong)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, (ulonglong)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", (ulonglong)i->dim, (ulonglong)(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 && i->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, NULL, 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, tn, elements2);
+                            (*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, init->type, elements);
+            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, itype, elements);
+                result = ae;
+                return;
+            }
+        }
+        result = i->exp;
+    }
+};
+
+Expression *initializerToExpression(Initializer *i, Type *t)
+{
+    InitToExpressionVisitor v = InitToExpressionVisitor(t);
+    i->accept(&v);
+    return v.result;
+}