Expression *Expression::integralPromotions(Scope *sc) { Expression *e = this; //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars()); switch (type->toBasetype()->ty) { case Tvoid: error("void has no value"); return new ErrorExp(); case Tint8: case Tuns8: case Tint16: case Tuns16: case Tbit: case Tbool: case Tchar: case Twchar: e = e->castTo(sc, Type::tint32); break; case Tdchar: e = e->castTo(sc, Type::tuns32); break; } return e; }
Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) { if (type == t) return this; AssocArrayLiteralExp *e = this; Type *typeb = type->toBasetype(); Type *tb = t->toBasetype(); if (tb->ty == Taarray && typeb->ty == Taarray && tb->nextOf()->toBasetype()->ty != Tvoid) { e = (AssocArrayLiteralExp *)copy(); e->keys = (Expressions *)keys->copy(); e->values = (Expressions *)values->copy(); assert(keys->dim == values->dim); for (size_t i = 0; i < keys->dim; i++) { Expression *ex = (Expression *)values->data[i]; ex = ex->castTo(sc, tb->nextOf()); e->values->data[i] = (void *)ex; ex = (Expression *)keys->data[i]; ex = ex->castTo(sc, ((TypeAArray *)tb)->index); e->keys->data[i] = (void *)ex; } e->type = t; return e; } L1: return e->Expression::castTo(sc, t); }
Expression *TupleExp::castTo(Scope *sc, Type *t) { TupleExp *e = (TupleExp *)copy(); e->exps = (Expressions *)exps->copy(); for (size_t i = 0; i < e->exps->dim; i++) { Expression *ex = (Expression *)e->exps->data[i]; ex = ex->castTo(sc, t); e->exps->data[i] = (void *)ex; } return e; }
Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) { #if 0 printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", toChars(), type->toChars(), t->toChars()); #endif if (type == t) return this; ArrayLiteralExp *e = this; Type *typeb = type->toBasetype(); Type *tb = t->toBasetype(); if ((tb->ty == Tarray || tb->ty == Tsarray) && (typeb->ty == Tarray || typeb->ty == Tsarray) && // Not trying to convert non-void[] to void[] !(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)) { if (tb->ty == Tsarray) { TypeSArray *tsa = (TypeSArray *)tb; if (elements->dim != tsa->dim->toInteger()) goto L1; } e = (ArrayLiteralExp *)copy(); e->elements = (Expressions *)elements->copy(); for (int i = 0; i < elements->dim; i++) { Expression *ex = (Expression *)elements->data[i]; ex = ex->castTo(sc, tb->nextOf()); e->elements->data[i] = (void *)ex; } e->type = t; return e; } if (tb->ty == Tpointer && typeb->ty == Tsarray) { e = (ArrayLiteralExp *)copy(); e->type = typeb->nextOf()->pointerTo(); } L1: return e->Expression::castTo(sc, t); }
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; semanticRun = PASSsemantic; if (scope) sc = scope; // The first enum member is special bool first = (this == (*ed->members)[0]); if (type) { type = type->semantic(loc, sc); assert(value); // "type id;" is not a valid enum member declaration } if (value) { Expression *e = value; assert(e->dyncast() == DYNCAST_EXPRESSION); e = e->semantic(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->type) continue; //printf("[%d] em = %s, em->semanticRun = %d\n", i, toChars(), em->semanticRun); Expression *e = em->value; e = e->implicitCastTo(sc, ed->memtype); e = e->ctfeInterpret(); e = e->castTo(sc, ed->type); if (e->op == TOKerror) ed->errors = true; em->value = e; } if (ed->errors) { ed->memtype = Type::terror; goto Lerrors; } } } if (ed->memtype && !type) { 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); } else if (type) { e = e->implicitCastTo(sc, type); 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); 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 = emax->semantic(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 = e->semantic(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 = e->semantic(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 = origValue->semantic(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 = etest->semantic(sc); etest = etest->ctfeInterpret(); if (etest->toInteger()) { error("has inexact value, due to loss of precision"); goto Lerrors; } } value = e; } assert(origValue); semanticRun = PASSsemanticdone; }
Expression *expandVar(int result, VarDeclaration *v) { //printf("expandVar(result = %d, v = %s)\n", result, v ? v->toChars() : "null"); Expression *e = NULL; if (v && (v->isConst() || v->isInvariant() || v->storage_class & STCmanifest)) { Type *tb = v->type->toBasetype(); if (result & WANTinterpret || v->storage_class & STCmanifest || (tb->ty != Tsarray && tb->ty != Tstruct) ) { if (v->init) { if (v->inuse) goto L1; Expression *ei = v->init->toExpression(); if (!ei) goto L1; if (ei->op == TOKconstruct || ei->op == TOKblit) { AssignExp *ae = (AssignExp *)ei; ei = ae->e2; if (ei->isConst() != 1 && ei->op != TOKstring) goto L1; if (ei->type != v->type) goto L1; } if (v->scope) { v->inuse++; e = ei->syntaxCopy(); e = e->semantic(v->scope); e = e->implicitCastTo(v->scope, v->type); v->scope = NULL; v->inuse--; } else 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); } e = e->optimize(result); } } L1: //if (e) printf("\te = %s, e->type = %s\n", e->toChars(), e->type->toChars()); return e; }
void EnumDeclaration::semantic(Scope *sc) { Type *t; Scope *sce; //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars()); //printf("EnumDeclaration::semantic() %s\n", toChars()); if (!members) // enum ident; return; if (!memtype && !isAnonymous()) { // Set memtype if we can to reduce fwd reference errors memtype = Type::tint32; // case 1) enum ident { ... } } if (symtab) // if already done { if (!scope) return; // semantic() already completed } else symtab = new DsymbolTable(); Scope *scx = NULL; if (scope) { sc = scope; scx = scope; // save so we don't make redundant copies scope = NULL; } if (sc->stc & STCdeprecated) isdeprecated = 1; parent = sc->parent; /* The separate, and distinct, cases are: * 1. enum { ... } * 2. enum : memtype { ... } * 3. enum ident { ... } * 4. enum ident : memtype { ... } */ 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 : new Scope(*sc); scope->setNoFree(); scope->module->addDeferredSemantic(this); printf("\tdeferring %s\n", toChars()); return; } } #if 0 // Decided to abandon this restriction for D 2.0 if (!memtype->isintegral()) { error("base type must be of integral type, not %s", memtype->toChars()); memtype = Type::tint32; } #endif } type = type->semantic(loc, sc); if (isAnonymous()) sce = sc; else { sce = sc->push(this); sce->parent = this; } if (members->dim == 0) error("enum %s must have at least one member", toChars()); int first = 1; Expression *elast = NULL; for (int i = 0; i < members->dim; i++) { EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); Expression *e; if (!em) /* The e->semantic(sce) can insert other symbols, such as * template instances and function literals. */ continue; //printf(" Enum member '%s'\n",em->toChars()); if (em->type) em->type = em->type->semantic(em->loc, sce); e = em->value; if (e) { assert(e->dyncast() == DYNCAST_EXPRESSION); e = e->semantic(sce); e = e->optimize(WANTvalue | WANTinterpret); if (memtype) { e = e->implicitCastTo(sce, memtype); e = e->optimize(WANTvalue | WANTinterpret); if (!isAnonymous()) e = e->castTo(sce, type); t = memtype; } else if (em->type) { e = e->implicitCastTo(sce, em->type); e = e->optimize(WANTvalue | WANTinterpret); assert(isAnonymous()); t = e->type; } else t = e->type; } else if (first) { if (memtype) t = memtype; else if (em->type) t = em->type; else t = Type::tint32; e = new IntegerExp(em->loc, 0, Type::tint32); e = e->implicitCastTo(sce, t); e = e->optimize(WANTvalue | WANTinterpret); if (!isAnonymous()) e = e->castTo(sce, type); } else { // Set value to (elast + 1). // But first check that (elast != t.max) assert(elast); e = new EqualExp(TOKequal, em->loc, elast, t->getProperty(0, Id::max)); e = e->semantic(sce); e = e->optimize(WANTvalue | WANTinterpret); if (e->toInteger()) error("overflow of enum value %s", elast->toChars()); // Now set e to (elast + 1) e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32)); e = e->semantic(sce); e = e->castTo(sce, elast->type); e = e->optimize(WANTvalue | WANTinterpret); } elast = e; em->value = e; // Add to symbol table only after evaluating 'value' if (isAnonymous()) { /* Anonymous enum members get added to enclosing scope. */ for (Scope *scx = sce; scx; scx = scx->enclosing) { if (scx->scopesym) { if (!scx->scopesym->symtab) scx->scopesym->symtab = new DsymbolTable(); em->addMember(sce, scx->scopesym, 1); break; } } } else em->addMember(sc, this, 1); /* Compute .min, .max and .default values. * If enum doesn't have a name, we can never identify the enum type, * so there is no purpose for a .min, .max or .default */ if (!isAnonymous()) { if (first) { defaultval = e; minval = e; maxval = e; } else { Expression *ec; /* 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 < minval) ec = new CmpExp(TOKlt, em->loc, e, minval); ec = ec->semantic(sce); ec = ec->optimize(WANTvalue | WANTinterpret); if (ec->toInteger()) minval = e; ec = new CmpExp(TOKgt, em->loc, e, maxval); ec = ec->semantic(sce); ec = ec->optimize(WANTvalue | WANTinterpret); if (ec->toInteger()) maxval = e; } } first = 0; } //printf("defaultval = %lld\n", defaultval); //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars()); if (sc != sce) sce->pop(); //members->print(); }
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) { //error("ICE"); return e; } Type *tb = v->type->toBasetype(); if (result & WANTinterpret || 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 L1; } Expression *ei = v->init->toExpression(); if (!ei) { if (v->storage_class & STCmanifest) v->error("enum cannot be initialized with %s", v->init->toChars()); goto L1; } if (ei->op == TOKconstruct || ei->op == TOKblit) { AssignExp *ae = (AssignExp *)ei; ei = ae->e2; if (result & WANTinterpret) { v->inuse++; ei = ei->optimize(result); v->inuse--; } else if (ei->isConst() != 1 && ei->op != TOKstring) 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(0, v->type); ei = ei->semantic(0); } else goto L1; } if (v->scope) { v->inuse++; e = ei->syntaxCopy(); e = e->semantic(v->scope); e = e->implicitCastTo(v->scope, v->type); // enabling this line causes test22 in test suite to fail //ei->type = e->type; v->scope = NULL; v->inuse--; } else 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; }
Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) { #if 0 printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", toChars(), type->toChars(), t->toChars()); #endif if (type == t) return this; ArrayLiteralExp *e = this; Type *typeb = type->toBasetype(); Type *tb = t->toBasetype(); if ((tb->ty == Tarray || tb->ty == Tsarray) && (typeb->ty == Tarray || typeb->ty == Tsarray) && // Not trying to convert non-void[] to void[] !(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)) { if (tb->ty == Tsarray) { TypeSArray *tsa = (TypeSArray *)tb; if (elements->dim != tsa->dim->toInteger()) goto L1; } e = (ArrayLiteralExp *)copy(); e->elements = (Expressions *)elements->copy(); for (size_t i = 0; i < elements->dim; i++) { Expression *ex = (*elements)[i]; ex = ex->castTo(sc, tb->nextOf()); (*e->elements)[i] = ex; } e->type = t; return e; } if (tb->ty == Tpointer && typeb->ty == Tsarray) { e = (ArrayLiteralExp *)copy(); e->type = typeb->nextOf()->pointerTo(); } #if DMDV2 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); if (elements->dim != tbase->dim->toInteger()) goto L1; e = (ArrayLiteralExp *)copy(); e->elements = (Expressions *)elements->copy(); Type *telement = tv->elementType(); for (size_t i = 0; i < elements->dim; i++) { Expression *ex = (*elements)[i]; ex = ex->castTo(sc, telement); (*e->elements)[i] = ex; } Expression *ev = new VectorExp(loc, e, tb); ev = ev->semantic(sc); return ev; } #endif L1: return e->Expression::castTo(sc, t); }