Mercurial > projects > ldc
view dmd/cast.c @ 1415:bac3931b3de3
Fix a behavioral change accidentally introduced by the move to the LLVM
commandline system: `-output-(bc|ll|s)` used to disable generation of an object
file unless explicitly requested with `-output-o`. Now they do so again.
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Sat, 23 May 2009 20:57:22 +0200 |
parents | 8026319762be |
children | def7a1d494fd |
line wrap: on
line source
// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com // License for redistribution is by either the Artistic License // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. #include <stdio.h> #include <assert.h> #include "rmem.h" #include "expression.h" #include "mtype.h" #include "utf.h" #include "declaration.h" #include "aggregate.h" /* ==================== implicitCast ====================== */ /************************************** * Do an implicit cast. * Issue error if it can't be done. */ Expression *Expression::implicitCastTo(Scope *sc, Type *t) { //printf("implicitCastTo(%s) => %s\n", type->toChars(), t->toChars()); if (implicitConvTo(t)) { TY tyfrom = type->toBasetype()->ty; TY tyto = t->toBasetype()->ty; if (global.params.warnings && Type::impcnvWarn[tyfrom][tyto] && op != TOKint64) { Expression *e = optimize(WANTflags | WANTvalue); if (e->op == TOKint64) return e->implicitCastTo(sc, t); if (tyfrom == Tint32 && (op == TOKadd || op == TOKmin || op == TOKand || op == TOKor || op == TOKxor) ) { /* This is really only a semi-kludge fix, * we really should look at the operands of op * and see if they are narrower types. * For example, b=b|b and b=b|7 and s=b+b should be allowed, * but b=b|i should be an error. */ ; } else { warning("implicit conversion of expression (%s) of type %s to %s can cause loss of data", toChars(), type->toChars(), t->toChars()); } } #if DMDV2 if (match == MATCHconst && t == type->constOf()) { Expression *e = copy(); e->type = t; return e; } #endif return castTo(sc, t); } Expression *e = optimize(WANTflags | WANTvalue); if (e != this) return e->implicitCastTo(sc, t); #if 0 printf("ty = %d\n", type->ty); print(); type->print(); printf("to:\n"); t->print(); printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco); //printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t); fflush(stdout); #endif if (!t->deco) { /* Can happen with: * enum E { One } * class A * { static void fork(EDG dg) { dg(E.One); } * alias void delegate(E) EDG; * } * Should eventually make it work. */ error("forward reference to type %s", t->toChars()); } else if (t->reliesOnTident()) error("forward reference to type %s", t->reliesOnTident()->toChars()); error("cannot implicitly convert expression (%s) of type %s to %s", toChars(), type->toChars(), t->toChars()); return castTo(sc, t); } /******************************************* * Return !=0 if we can implicitly convert this to type t. * Don't do the actual cast. */ MATCH Expression::implicitConvTo(Type *t) { #if 0 printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif //static int nest; if (++nest == 10) halt(); if (!type) { error("%s is not an expression", toChars()); type = Type::terror; } if (t->ty == Tbit && isBit()) return MATCHconvert; Expression *e = optimize(WANTvalue | WANTflags); if (e != this) { //printf("optimzed to %s\n", e->toChars()); return e->implicitConvTo(t); } MATCH match = type->implicitConvTo(t); if (match) return match; #if 0 Type *tb = t->toBasetype(); if (tb->ty == Tdelegate) { TypeDelegate *td = (TypeDelegate *)tb; TypeFunction *tf = (TypeFunction *)td->nextOf(); if (!tf->varargs && !(tf->arguments && tf->arguments->dim) ) { match = type->implicitConvTo(tf->nextOf()); if (match) return match; if (tf->nextOf()->toBasetype()->ty == Tvoid) return MATCHconvert; } } #endif return MATCHnomatch; } MATCH IntegerExp::implicitConvTo(Type *t) { #if 0 printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif if (type->equals(t)) return MATCHexact; enum TY ty = type->toBasetype()->ty; enum TY toty = t->toBasetype()->ty; if (type->implicitConvTo(t) == MATCHnomatch && t->ty == Tenum) { return MATCHnomatch; } switch (ty) { case Tbit: case Tbool: value &= 1; ty = Tint32; break; case Tint8: value = (signed char)value; ty = Tint32; break; case Tchar: case Tuns8: value &= 0xFF; ty = Tint32; break; case Tint16: value = (short)value; ty = Tint32; break; case Tuns16: case Twchar: value &= 0xFFFF; ty = Tint32; break; case Tint32: value = (int)value; break; case Tuns32: case Tdchar: value &= 0xFFFFFFFF; ty = Tuns32; break; default: break; } // Only allow conversion if no change in value switch (toty) { case Tbit: case Tbool: if ((value & 1) != value) goto Lno; goto Lyes; case Tint8: if ((signed char)value != value) goto Lno; goto Lyes; case Tchar: case Tuns8: //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); if ((unsigned char)value != value) goto Lno; goto Lyes; case Tint16: if ((short)value != value) goto Lno; goto Lyes; case Tuns16: if ((unsigned short)value != value) goto Lno; goto Lyes; case Tint32: if (ty == Tuns32) { } else if ((int)value != value) goto Lno; goto Lyes; case Tuns32: if (ty == Tint32) { } else if ((unsigned)value != value) goto Lno; goto Lyes; case Tdchar: if (value > 0x10FFFFUL) goto Lno; goto Lyes; case Twchar: if ((unsigned short)value != value) goto Lno; goto Lyes; case Tfloat32: { volatile float f; if (type->isunsigned()) { f = (float)value; if (f != value) goto Lno; } else { f = (float)(long long)value; if (f != (long long)value) goto Lno; } goto Lyes; } case Tfloat64: { volatile double f; if (type->isunsigned()) { f = (double)value; if (f != value) goto Lno; } else { f = (double)(long long)value; if (f != (long long)value) goto Lno; } goto Lyes; } case Tfloat80: { volatile long double f; if (type->isunsigned()) { f = (long double)value; if (f != value) goto Lno; } else { f = (long double)(long long)value; if (f != (long long)value) goto Lno; } goto Lyes; } } return Expression::implicitConvTo(t); Lyes: //printf("MATCHconvert\n"); return MATCHconvert; Lno: //printf("MATCHnomatch\n"); return MATCHnomatch; } MATCH NullExp::implicitConvTo(Type *t) { #if 0 printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n", toChars(), type->toChars(), t->toChars(), committed); #endif if (this->type->equals(t)) return MATCHexact; // NULL implicitly converts to any pointer type or dynamic array if (type->ty == Tpointer && type->next->ty == Tvoid) { if (t->ty == Ttypedef) t = ((TypeTypedef *)t)->sym->basetype; if (t->ty == Tpointer || t->ty == Tarray || t->ty == Taarray || t->ty == Tclass || t->ty == Tdelegate) return committed ? MATCHconvert : MATCHexact; } return Expression::implicitConvTo(t); } #if DMDV2 MATCH StructLiteralExp::implicitConvTo(Type *t) { #if 0 printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif MATCH m = Expression::implicitConvTo(t); if (m != MATCHnomatch) return m; if (type->ty == t->ty && type->ty == Tstruct && ((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym) { m = MATCHconst; for (int i = 0; i < elements->dim; i++) { Expression *e = (Expression *)elements->data[i]; Type *te = e->type; if (t->mod == 0) te = te->mutableOf(); else { assert(t->mod == MODinvariant); te = te->invariantOf(); } MATCH m2 = e->implicitConvTo(te); //printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2); if (m2 < m) m = m2; } } return m; } #endif MATCH StringExp::implicitConvTo(Type *t) { MATCH m; #if 0 printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", toChars(), committed, type->toChars(), t->toChars()); #endif if (!committed) { if (!committed && t->ty == Tpointer && t->next->ty == Tvoid) { return MATCHnomatch; } if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer) { if (type->next->ty == Tchar) { switch (t->ty) { case Tsarray: if (type->ty == Tsarray && ((TypeSArray *)type)->dim->toInteger() != ((TypeSArray *)t)->dim->toInteger()) return MATCHnomatch; goto L1; case Tarray: goto L1; case Tpointer: L1: if (t->next->ty == Tchar) return MATCHexact; else if (t->next->ty == Twchar) return MATCHexact; else if (t->next->ty == Tdchar) return MATCHexact; break; } } } } return Expression::implicitConvTo(t); #if 0 m = (MATCH)type->implicitConvTo(t); if (m) { return m; } return MATCHnomatch; #endif } MATCH ArrayLiteralExp::implicitConvTo(Type *t) { MATCH result = MATCHexact; #if 0 printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif Type *typeb = type->toBasetype(); Type *tb = t->toBasetype(); if ((tb->ty == Tarray || tb->ty == Tsarray) && (typeb->ty == Tarray || typeb->ty == Tsarray)) { if (tb->ty == Tsarray) { TypeSArray *tsa = (TypeSArray *)tb; if (elements->dim != tsa->dim->toInteger()) result = MATCHnomatch; } for (int i = 0; i < elements->dim; i++) { Expression *e = (Expression *)elements->data[i]; MATCH m = (MATCH)e->implicitConvTo(tb->nextOf()); if (m < result) result = m; // remember worst match if (result == MATCHnomatch) break; // no need to check for worse } return result; } else return Expression::implicitConvTo(t); } MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) { MATCH result = MATCHexact; Type *typeb = type->toBasetype(); Type *tb = t->toBasetype(); if (tb->ty == Taarray && typeb->ty == Taarray) { for (size_t i = 0; i < keys->dim; i++) { Expression *e = (Expression *)keys->data[i]; MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->key); if (m < result) result = m; // remember worst match if (result == MATCHnomatch) break; // no need to check for worse e = (Expression *)values->data[i]; m = (MATCH)e->implicitConvTo(tb->nextOf()); if (m < result) result = m; // remember worst match if (result == MATCHnomatch) break; // no need to check for worse } return result; } else return Expression::implicitConvTo(t); } MATCH AddrExp::implicitConvTo(Type *t) { #if 0 printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif MATCH result; result = type->implicitConvTo(t); //printf("\tresult = %d\n", result); if (result == MATCHnomatch) { // Look for pointers to functions where the functions are overloaded. VarExp *ve; FuncDeclaration *f; t = t->toBasetype(); if (type->ty == Tpointer && type->next->ty == Tfunction && t->ty == Tpointer && t->next->ty == Tfunction && e1->op == TOKvar) { ve = (VarExp *)e1; f = ve->var->isFuncDeclaration(); if (f && f->overloadExactMatch(t->next, m)) result = MATCHexact; } } //printf("\tresult = %d\n", result); return result; } MATCH SymOffExp::implicitConvTo(Type *t) { #if 0 printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif MATCH result; result = type->implicitConvTo(t); //printf("\tresult = %d\n", result); if (result == MATCHnomatch) { // Look for pointers to functions where the functions are overloaded. FuncDeclaration *f; t = t->toBasetype(); if (type->ty == Tpointer && type->next->ty == Tfunction && t->ty == Tpointer && t->next->ty == Tfunction) { f = var->isFuncDeclaration(); if (f && f->overloadExactMatch(t->next, m)) result = MATCHexact; } } //printf("\tresult = %d\n", result); return result; } MATCH DelegateExp::implicitConvTo(Type *t) { #if 0 printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif MATCH result; result = type->implicitConvTo(t); if (result == 0) { // Look for pointers to functions where the functions are overloaded. FuncDeclaration *f; t = t->toBasetype(); if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction && t->ty == Tdelegate && t->nextOf()->ty == Tfunction) { if (func && func->overloadExactMatch(t->nextOf(), m)) result = MATCHexact; } } return result; } MATCH CondExp::implicitConvTo(Type *t) { MATCH m1; MATCH m2; m1 = e1->implicitConvTo(t); m2 = e2->implicitConvTo(t); // Pick the worst match return (m1 < m2) ? m1 : m2; } /* ==================== castTo ====================== */ /************************************** * Do an explicit cast. */ Expression *Expression::castTo(Scope *sc, Type *t) { //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars()); #if 0 printf("Expression::castTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif if (type == t) return this; Expression *e = this; Type *tb = t->toBasetype(); Type *typeb = type->toBasetype(); if (tb != typeb) { // Do (type *) cast of (type [dim]) if (tb->ty == Tpointer && typeb->ty == Tsarray ) { //printf("Converting [dim] to *\n"); if (typeb->size(loc) == 0) e = new NullExp(loc); else e = new AddrExp(loc, e); } #if 0 else if (tb->ty == Tdelegate && type->ty != Tdelegate) { TypeDelegate *td = (TypeDelegate *)tb; TypeFunction *tf = (TypeFunction *)td->nextOf(); return toDelegate(sc, tf->nextOf()); } #endif else { e = new CastExp(loc, e, tb); } } else { e = e->copy(); // because of COW for assignment to e->type } assert(e != this); e->type = t; //printf("Returning: %s\n", e->toChars()); return e; } Expression *RealExp::castTo(Scope *sc, Type *t) { Expression *e = this; if (type != t) { if ((type->isreal() && t->isreal()) || (type->isimaginary() && t->isimaginary()) ) { e = copy(); e->type = t; } else e = Expression::castTo(sc, t); } return e; } Expression *ComplexExp::castTo(Scope *sc, Type *t) { Expression *e = this; if (type != t) { if (type->iscomplex() && t->iscomplex()) { e = copy(); e->type = t; } else e = Expression::castTo(sc, t); } return e; } Expression *NullExp::castTo(Scope *sc, Type *t) { NullExp *e; Type *tb; //printf("NullExp::castTo(t = %p)\n", t); if (type == t) { committed = 1; return this; } e = (NullExp *)copy(); e->committed = 1; tb = t->toBasetype(); e->type = type->toBasetype(); if (tb != e->type) { // NULL implicitly converts to any pointer type or dynamic array if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid && (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray || tb->ty == Tdelegate)) { #if 0 if (tb->ty == Tdelegate) { TypeDelegate *td = (TypeDelegate *)tb; TypeFunction *tf = (TypeFunction *)td->nextOf(); if (!tf->varargs && !(tf->arguments && tf->arguments->dim) ) { return Expression::castTo(sc, t); } } #endif } else { return e->Expression::castTo(sc, t); } } e->type = t; return e; } Expression *StringExp::castTo(Scope *sc, Type *t) { /* This follows copy-on-write; any changes to 'this' * will result in a copy. * The this->string member is considered immutable. */ StringExp *se; Type *tb; int copied = 0; //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed); if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) { error("cannot convert string literal to void*"); } se = this; if (!committed) { se = (StringExp *)copy(); se->committed = 1; copied = 1; } if (type == t) { return se; } tb = t->toBasetype(); //printf("\ttype = %s\n", type->toChars()); if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate) return Expression::castTo(sc, t); Type *typeb = type->toBasetype(); if (typeb == tb) { if (!copied) { se = (StringExp *)copy(); copied = 1; } se->type = t; return se; } if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer) { if (!copied) { se = (StringExp *)copy(); copied = 1; } goto Lcast; } if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer) { if (!copied) { se = (StringExp *)copy(); copied = 1; } goto Lcast; } if (typeb->nextOf()->size() == tb->nextOf()->size()) { if (!copied) { se = (StringExp *)copy(); copied = 1; } if (tb->ty == Tsarray) goto L2; // handle possible change in static array dimension se->type = t; return se; } if (committed) goto Lcast; #define X(tf,tt) ((tf) * 256 + (tt)) { OutBuffer buffer; size_t newlen = 0; int tfty = typeb->nextOf()->toBasetype()->ty; int ttty = tb->nextOf()->toBasetype()->ty; switch (X(tfty, ttty)) { case X(Tchar, Tchar): case X(Twchar,Twchar): case X(Tdchar,Tdchar): break; case X(Tchar, Twchar): for (size_t u = 0; u < len;) { unsigned c; char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); if (p) error("%s", p); else buffer.writeUTF16(c); } newlen = buffer.offset / 2; buffer.writeUTF16(0); goto L1; case X(Tchar, Tdchar): for (size_t u = 0; u < len;) { unsigned c; char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); if (p) error("%s", p); buffer.write4(c); newlen++; } buffer.write4(0); goto L1; case X(Twchar,Tchar): for (size_t u = 0; u < len;) { unsigned c; char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); if (p) error("%s", p); else buffer.writeUTF8(c); } newlen = buffer.offset; buffer.writeUTF8(0); goto L1; case X(Twchar,Tdchar): for (size_t u = 0; u < len;) { unsigned c; char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); if (p) error("%s", p); buffer.write4(c); newlen++; } buffer.write4(0); goto L1; case X(Tdchar,Tchar): for (size_t u = 0; u < len; u++) { unsigned c = ((unsigned *)se->string)[u]; if (!utf_isValidDchar(c)) error("invalid UCS-32 char \\U%08x", c); else buffer.writeUTF8(c); newlen++; } newlen = buffer.offset; buffer.writeUTF8(0); goto L1; case X(Tdchar,Twchar): for (size_t u = 0; u < len; u++) { unsigned c = ((unsigned *)se->string)[u]; if (!utf_isValidDchar(c)) error("invalid UCS-32 char \\U%08x", c); else buffer.writeUTF16(c); newlen++; } newlen = buffer.offset / 2; buffer.writeUTF16(0); goto L1; L1: if (!copied) { se = (StringExp *)copy(); copied = 1; } se->string = buffer.extractData(); se->len = newlen; se->sz = tb->nextOf()->size(); break; default: assert(typeb->nextOf()->size() != tb->nextOf()->size()); goto Lcast; } } #undef X L2: assert(copied); // See if need to truncate or extend the literal if (tb->ty == Tsarray) { int dim2 = ((TypeSArray *)tb)->dim->toInteger(); //printf("dim from = %d, to = %d\n", se->len, dim2); // Changing dimensions if (dim2 != se->len) { // Copy when changing the string literal unsigned newsz = se->sz; void *s; int d; d = (dim2 < se->len) ? dim2 : se->len; s = (unsigned char *)mem.malloc((dim2 + 1) * newsz); memcpy(s, se->string, d * newsz); // Extend with 0, add terminating 0 memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz); se->string = s; se->len = dim2; } } se->type = t; return se; Lcast: Expression *e = new CastExp(loc, se, t); e->type = t; // so semantic() won't be run on e return e; } Expression *AddrExp::castTo(Scope *sc, Type *t) { Type *tb; #if 0 printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif Expression *e = this; tb = t->toBasetype(); type = type->toBasetype(); if (tb != type) { // Look for pointers to functions where the functions are overloaded. VarExp *ve; FuncDeclaration *f; if (type->ty == Tpointer && type->next->ty == Tfunction && tb->ty == Tpointer && tb->next->ty == Tfunction && e1->op == TOKvar) { ve = (VarExp *)e1; f = ve->var->isFuncDeclaration(); if (f) { f = f->overloadExactMatch(tb->next, m); if (f) { e = new VarExp(loc, f); e->type = f->type; e = new AddrExp(loc, e); e->type = t; return e; } } } e = Expression::castTo(sc, t); } e->type = t; return e; } 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); } 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 *SymOffExp::castTo(Scope *sc, Type *t) { Type *tb; #if 0 printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif Expression *e = this; tb = t->toBasetype(); type = type->toBasetype(); if (tb != type) { // Look for pointers to functions where the functions are overloaded. FuncDeclaration *f; if (type->ty == Tpointer && type->next->ty == Tfunction && tb->ty == Tpointer && tb->next->ty == Tfunction) { f = var->isFuncDeclaration(); if (f) { f = f->overloadExactMatch(tb->next, m); if (f) { e = new SymOffExp(loc, f, 0); e->type = t; return e; } } } e = Expression::castTo(sc, t); } e->type = t; return e; } Expression *DelegateExp::castTo(Scope *sc, Type *t) { Type *tb; #if 0 printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif Expression *e = this; static char msg[] = "cannot form delegate due to covariant return type"; tb = t->toBasetype(); type = type->toBasetype(); if (tb != type) { // Look for delegates to functions where the functions are overloaded. FuncDeclaration *f; if (type->ty == Tdelegate && type->next->ty == Tfunction && tb->ty == Tdelegate && tb->next->ty == Tfunction) { if (func) { f = func->overloadExactMatch(tb->next, m); if (f) { int offset; if (f->tintro && f->tintro->next->isBaseOf(f->type->next, &offset) && offset) error("%s", msg); e = new DelegateExp(loc, e1, f); e->type = t; return e; } if (func->tintro) error("%s", msg); } } e = Expression::castTo(sc, t); } else { int offset; if (func->tintro && func->tintro->next->isBaseOf(func->type->next, &offset) && offset) error("%s", msg); } e->type = t; return e; } Expression *CondExp::castTo(Scope *sc, Type *t) { Expression *e = this; if (type != t) { if (1 || e1->op == TOKstring || e2->op == TOKstring) { e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t)); e->type = t; } else e = Expression::castTo(sc, t); } return e; } /* ==================== ====================== */ /**************************************** * Scale addition/subtraction to/from pointer. */ Expression *BinExp::scaleFactor(Scope *sc) { d_uns64 stride; Type *t1b = e1->type->toBasetype(); Type *t2b = e2->type->toBasetype(); if (t1b->ty == Tpointer && t2b->isintegral()) { // Need to adjust operator by the stride // Replace (ptr + int) with (ptr + (int * stride)) Type *t = Type::tptrdiff_t; stride = t1b->nextOf()->size(loc); if (!t->equals(t2b)) e2 = e2->castTo(sc, t); // LDC: llvm uses typesafe pointer arithmetic #if !IN_LLVM if (t1b->next->isbit()) // BUG: should add runtime check for misaligned offsets // This perhaps should be done by rewriting as &p[i] // and letting back end do it. e2 = new UshrExp(loc, e2, new IntegerExp(0, 3, t)); else e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t)); #endif e2->type = t; type = e1->type; } else if (t2b->ty == Tpointer && t1b->isintegral()) { // Need to adjust operator by the stride // Replace (int + ptr) with (ptr + (int * stride)) Type *t = Type::tptrdiff_t; Expression *e; stride = t2b->nextOf()->size(loc); if (!t->equals(t1b)) e = e1->castTo(sc, t); else e = e1; #if !IN_LLVM if (t2b->next->isbit()) // BUG: should add runtime check for misaligned offsets e = new UshrExp(loc, e, new IntegerExp(0, 3, t)); else e = new MulExp(loc, e, new IntegerExp(0, stride, t)); #endif e->type = t; type = e2->type; e1 = e2; e2 = e; } return this; } /************************************ * Bring leaves to common type. */ Expression *BinExp::typeCombine(Scope *sc) { Type *t1; Type *t2; Type *t; TY ty; //printf("BinExp::typeCombine()\n"); //dump(0); e1 = e1->integralPromotions(sc); e2 = e2->integralPromotions(sc); // BUG: do toBasetype() t1 = e1->type; t2 = e2->type; assert(t1); //if (t1) printf("\tt1 = %s\n", t1->toChars()); //if (t2) printf("\tt2 = %s\n", t2->toChars()); #ifdef DEBUG if (!t2) printf("\te2 = '%s'\n", e2->toChars()); #endif assert(t2); Type *t1b = t1->toBasetype(); Type *t2b = t2->toBasetype(); ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty]; if (ty != Terror) { TY ty1; TY ty2; ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty]; ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty]; if (t1b->ty == ty1) // if no promotions { if (t1 == t2) { if (!type) type = t1; return this; } if (t1b == t2b) { if (!type) type = t1b; return this; } } if (!type) type = Type::basic[ty]; t1 = Type::basic[ty1]; t2 = Type::basic[ty2]; e1 = e1->castTo(sc, t1); e2 = e2->castTo(sc, t2); #if 0 if (type != Type::basic[ty]) { t = type; type = Type::basic[ty]; return castTo(sc, t); } #endif //printf("after typeCombine():\n"); //dump(0); //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2); return this; } t = t1; if (t1 == t2) { if ((t1->ty == Tstruct || t1->ty == Tclass) && (op == TOKmin || op == TOKadd)) goto Lincompatible; } else if (t1->isintegral() && t2->isintegral()) { printf("t1 = %s, t2 = %s\n", t1->toChars(), t2->toChars()); int sz1 = t1->size(); int sz2 = t2->size(); int sign1 = t1->isunsigned() == 0; int sign2 = t2->isunsigned() == 0; if (sign1 == sign2) { if (sz1 < sz2) goto Lt2; else goto Lt1; } if (!sign1) { if (sz1 >= sz2) goto Lt1; else goto Lt2; } else { if (sz2 >= sz1) goto Lt2; else goto Lt1; } } else if (t1->ty == Tpointer && t2->ty == Tpointer) { // Bring pointers to compatible type Type *t1n = t1->next; Type *t2n = t2->next; //t1->print(); //t2->print(); //if (t1n == t2n) *(char *)0 = 0; assert(t1n != t2n); if (t1n->ty == Tvoid) // pointers to void are always compatible t = t2; else if (t2n->ty == Tvoid) ; else if (t1n->ty == Tclass && t2n->ty == Tclass) { ClassDeclaration *cd1 = t1n->isClassHandle(); ClassDeclaration *cd2 = t2n->isClassHandle(); int offset; if (cd1->isBaseOf(cd2, &offset)) { if (offset) e2 = e2->castTo(sc, t); } else if (cd2->isBaseOf(cd1, &offset)) { t = t2; if (offset) e1 = e1->castTo(sc, t); } else goto Lincompatible; } else goto Lincompatible; } else if ((t1->ty == Tsarray || t1->ty == Tarray) && e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid) { /* (T[n] op void*) * (T[] op void*) */ goto Lx1; } else if ((t2->ty == Tsarray || t2->ty == Tarray) && e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid) { /* (void* op T[n]) * (void* op T[]) */ goto Lx2; } else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) { goto Lt2; } else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1)) { goto Lt1; } else if (t1->ty == Tclass || t2->ty == Tclass) { while (1) { int i1 = e2->implicitConvTo(t1); int i2 = e1->implicitConvTo(t2); if (i1 && i2) { // We have the case of class vs. void*, so pick class if (t1->ty == Tpointer) i1 = 0; else if (t2->ty == Tpointer) i2 = 0; } if (i2) { goto Lt2; } else if (i1) { goto Lt1; } else if (t1->ty == Tclass && t2->ty == Tclass) { TypeClass *tc1 = (TypeClass *)t1; TypeClass *tc2 = (TypeClass *)t2; /* Pick 'tightest' type */ ClassDeclaration *cd1 = tc1->sym->baseClass; ClassDeclaration *cd2 = tc2->sym->baseClass; if (cd1 && cd2) { t1 = cd1->type; t2 = cd2->type; } else if (cd1) t1 = cd1->type; else if (cd2) t2 = cd2->type; else goto Lincompatible; } else goto Lincompatible; } } else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2)) { goto Lt2; } //else if (e2->op == TOKstring) { printf("test2\n"); } else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1)) { goto Lt1; } else if (t1->ty == Tsarray && t2->ty == Tsarray && e2->implicitConvTo(t1->nextOf()->arrayOf())) { Lx1: t = t1->nextOf()->arrayOf(); e1 = e1->castTo(sc, t); e2 = e2->castTo(sc, t); } else if (t1->ty == Tsarray && t2->ty == Tsarray && e1->implicitConvTo(t2->nextOf()->arrayOf())) { Lx2: t = t2->nextOf()->arrayOf(); e1 = e1->castTo(sc, t); e2 = e2->castTo(sc, t); } else if (t1->isintegral() && t2->isintegral()) { assert(0); } else if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf())) { // T[] op T e2 = e2->castTo(sc, t1->nextOf()); t = t1->nextOf()->arrayOf(); } else if (e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) { // T op T[] e1 = e1->castTo(sc, t2->nextOf()); t = t2->nextOf()->arrayOf(); //printf("test %s\n", e->toChars()); e1 = e1->optimize(WANTvalue); if (isCommutative() && e1->isConst()) { /* Swap operands to minimize number of functions generated */ //printf("swap %s\n", e->toChars()); Expression *tmp = e1; e1 = e2; e2 = tmp; } } else { Lincompatible: incompatibleTypes(); type = Type::terror; e1 = new ErrorExp(); e2 = new ErrorExp(); } Lret: if (!type) type = t; //dump(0); return this; Lt1: e2 = e2->castTo(sc, t1); t = t1; goto Lret; Lt2: e1 = e1->castTo(sc, t2); t = t2; goto Lret; } /*********************************** * Do integral promotions (convertchk). * Don't convert <array of> to <pointer to> */ 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"); break; 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; }