| |
| /* 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; |
| } |