Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); int wantOptimize = needInterpret ? WANTinterpret|WANTvalue : WANTvalue; int olderrors = global.errors; exp = exp->optimize(wantOptimize); if (!global.gag && olderrors != global.errors) return this; // Failed, suppress duplicate error messages if (exp->op == TOKtype) exp->error("initializer must be an expression, not '%s'", exp->toChars()); // Make sure all pointers are constants if (needInterpret && hasNonConstPointers(exp)) { exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars()); return this; } 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 (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray) { StringExp *se = (StringExp *)exp; if (!se->committed && se->type->ty == Tsarray && ((TypeSArray *)se->type)->dim->toInteger() < ((TypeSArray *)t)->dim->toInteger()) { exp = se->castTo(sc, t); goto L1; } } // Look for the case of statically initializing an array // with a single member. if (tb->ty == Tsarray && !tb->nextOf()->equals(exp->type->toBasetype()->nextOf()) && exp->implicitConvTo(tb->nextOf()) ) { t = tb->nextOf(); } exp = exp->implicitCastTo(sc, t); L1: exp = exp->optimize(wantOptimize); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; }
Initializer *ExpInitializer::semantic(Scope *sc, Type *t) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); exp = exp->optimize(WANTvalue | WANTinterpret); 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 (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray) { StringExp *se = (StringExp *)exp; if (!se->committed && se->type->ty == Tsarray && ((TypeSArray *)se->type)->dim->toInteger() < ((TypeSArray *)t)->dim->toInteger()) { exp = se->castTo(sc, t); goto L1; } } // Look for the case of statically initializing an array // with a single member. if (tb->ty == Tsarray && !tb->nextOf()->equals(exp->type->toBasetype()->nextOf()) && exp->implicitConvTo(tb->nextOf()) ) { t = tb->nextOf(); } exp = exp->implicitCastTo(sc, t); L1: exp = exp->optimize(WANTvalue | WANTinterpret); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; }
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); if (needInterpret) exp = exp->ctfeSemantic(sc); else exp = exp->semantic(sc); exp = resolveProperties(sc, exp); if (exp->op == TOKerror) return this; int olderrors = global.errors; if (needInterpret) exp = exp->ctfeInterpret(); else exp = exp->optimize(WANTvalue); if (!global.gag && olderrors != global.errors) return this; // Failed, suppress duplicate error messages if (exp->op == TOKtype) { exp->error("initializer must be an expression, not '%s'", exp->toChars()); return new ErrorInitializer(); } // Make sure all pointers are constants if (needInterpret && hasNonConstPointers(exp)) { exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars()); return new ErrorInitializer(); } Type *tb = t->toBasetype(); Type *ti = exp->type->toBasetype(); if (exp->op == TOKtuple && expandTuples && !exp->implicitConvTo(t)) return new ExpInitializer(loc, exp); /* 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 (exp->op == TOKstring && tb->ty == Tsarray && ti->ty == Tsarray) { StringExp *se = (StringExp *)exp; if (!se->committed && se->type->ty == Tsarray && ((TypeSArray *)se->type)->dim->toInteger() < ((TypeSArray *)t)->dim->toInteger()) { 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)) && !exp->implicitConvTo(t)) { StructDeclaration *sd = ((TypeStruct *)tb)->sym; if (sd->ctor) { // Rewrite as S().ctor(exp) Expression *e; e = new StructLiteralExp(loc, sd, NULL); e = new DotIdExp(loc, e, Id::ctor); e = new CallExp(loc, e, exp); e = e->semantic(sc); if (needInterpret) exp = e->ctfeInterpret(); else 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()) && 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(); } exp = exp->implicitCastTo(sc, t); if (exp->op == TOKerror) return this; L1: if (needInterpret) exp = exp->ctfeInterpret(); else exp = exp->optimize(WANTvalue); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; }
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); if (needInterpret) sc = sc->startCTFE(); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); if (needInterpret) sc = sc->endCTFE(); if (exp->op == TOKerror) return new ErrorInitializer(); 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 (exp->implicitConvTo(t)) { exp = exp->implicitCastTo(sc, t); } exp = exp->ctfeInterpret(); } else { exp = exp->optimize(WANTvalue); } if (!global.gag && olderrors != global.errors) return this; // Failed, suppress duplicate error messages if (exp->op == TOKtype) { exp->error("initializer must be an expression, not '%s'", exp->toChars()); return new ErrorInitializer(); } // Make sure all pointers are constants if (needInterpret && hasNonConstPointers(exp)) { exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars()); return new ErrorInitializer(); } Type *tb = t->toBasetype(); Type *ti = exp->type->toBasetype(); if (exp->op == TOKtuple && expandTuples && !exp->implicitConvTo(t)) return new ExpInitializer(loc, exp); /* 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 (exp->op == TOKstring && tb->ty == Tsarray && ti->ty == Tsarray) { StringExp *se = (StringExp *)exp; if (!se->committed && se->type->ty == Tsarray && ((TypeSArray *)se->type)->dim->toInteger() < ((TypeSArray *)t)->dim->toInteger()) { 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)) && !exp->implicitConvTo(t)) { StructDeclaration *sd = ((TypeStruct *)tb)->sym; if (sd->ctor) { // Rewrite as S().ctor(exp) Expression *e; e = new StructLiteralExp(loc, sd, NULL); e = new DotIdExp(loc, e, Id::ctor); e = new CallExp(loc, e, exp); e = e->semantic(sc); if (needInterpret) exp = e->ctfeInterpret(); else 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()) && 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 (exp->implicitConvTo(t)) { exp = 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 && exp->implicitConvTo(tb->nextOf()->arrayOf()) > MATCHnomatch) { uinteger_t dim1 = ((TypeSArray *)tb)->dim->toInteger(); uinteger_t dim2 = dim1; if (exp->op == TOKarrayliteral) { ArrayLiteralExp *ale = (ArrayLiteralExp *)exp; dim2 = ale->elements ? ale->elements->dim : 0; } else if (exp->op == TOKslice) { Type *tx = toStaticArrayType((SliceExp *)exp); if (tx) dim2 = ((TypeSArray *)tx)->dim->toInteger(); } if (dim1 != dim2) { exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2); exp = new ErrorExp(); } } exp = exp->implicitCastTo(sc, t); } if (exp->op == TOKerror) return this; L1: if (needInterpret) exp = exp->ctfeInterpret(); else exp = exp->optimize(WANTvalue); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; }
/*************************************** * 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->length((int)tb->nextOf()->size()) < ((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] = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e); } return true; }