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