view dmd/CastExp.d @ 178:e3afd1303184

Many small bugs fixed Made all classes derive from TObject to detect memory leaks (functionality is disabled for now) Began work on overriding backend memory allocations (to avoid memory leaks)
author korDen
date Sun, 17 Oct 2010 07:42:00 +0400
parents af1bebfd96a4
children b0d41ff5e0df
line wrap: on
line source

module dmd.CastExp;

import dmd.common;
import dmd.Expression;
import dmd.GlobalExpressions;
import dmd.TY;
import dmd.TypeStruct;
import dmd.ErrorExp;
import dmd.TypeExp;
import dmd.DotIdExp;
import dmd.CallExp;
import dmd.Global;
import dmd.Id;
import dmd.Identifier;
import dmd.BinExp;
import dmd.UnaExp;
import dmd.VarExp;
import dmd.Token;
import dmd.VarDeclaration;
import dmd.InterState;
import dmd.MATCH;
import dmd.Type;
import dmd.OutBuffer;
import dmd.Loc;
import dmd.Scope;
import dmd.IntRange;
import dmd.IRState;
import dmd.ArrayTypes;
import dmd.HdrGenState;
import dmd.MOD;
import dmd.TOK;
import dmd.WANT;
import dmd.ClassDeclaration;

import dmd.Optimize;
import dmd.PREC;
import dmd.Cast;

import dmd.codegen.Util;
import dmd.backend.elem;
import dmd.backend.mTY;
import dmd.backend.Util;
import dmd.backend.TYM;
import dmd.backend.OPER;
import dmd.backend.RTLSYM;
import dmd.expression.Util;

class CastExp : UnaExp
{
	// Possible to cast to one type while painting to another type
	Type to;				// type to cast to
	MOD mod;				// MODxxxxx

	this(Loc loc, Expression e, Type t)
	{
		register();

		super(loc, TOK.TOKcast, CastExp.sizeof, e);
		to = t;
		this.mod = cast(MOD)~0;
	}

	this(Loc loc, Expression e, MOD mod)
	{
		register();

		super(loc, TOK.TOKcast, CastExp.sizeof, e);
		to = null;
		this.mod = mod;
	}

	override Expression syntaxCopy()
	{
		return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy())
	      : new CastExp(loc, e1.syntaxCopy(), mod);
	}

	override Expression semantic(Scope sc)
	{
		Expression e;
		BinExp b;
		UnaExp u;

version (LOGSEMANTIC) {
		printf("CastExp.semantic('%s')\n", toChars());
}

		//static int x; assert(++x < 10);

		if (type)
			return this;
		super.semantic(sc);
		if (e1.type)		// if not a tuple
		{
			e1 = resolveProperties(sc, e1);

			if (!to)
			{
				/* Handle cast(const) and cast(immutable), etc.
				 */
				to = e1.type.castMod(mod);
			}
			else
				to = to.semantic(loc, sc);

			if (!to.equals(e1.type))
			{
				e = op_overload(sc);
				if (e)
				{
				return e.implicitCastTo(sc, to);
				}
			}

			if (e1.op == TOKtemplate)
			{
			    error("cannot cast template %s to type %s", e1.toChars(), to.toChars());
			    return new ErrorExp();
			}

			Type t1b = e1.type.toBasetype();
			Type tob = to.toBasetype();
			if (tob.ty == TY.Tstruct &&
				!tob.equals(t1b) &&
				(cast(TypeStruct)tob).sym.search(Loc(0), Id.call, 0)
			   )
			{
				/* Look to replace:
				 *	cast(S)t
				 * with:
				 *	S(t)
				 */

				// Rewrite as to.call(e1)
				e = new TypeExp(loc, to);
				e = new DotIdExp(loc, e, Id.call);
				e = new CallExp(loc, e, e1);
				e = e.semantic(sc);
				return e;
			}
			
			// Struct casts are possible only when the sizes match
			if (tob.ty == Tstruct || t1b.ty == Tstruct)
			{
				size_t fromsize = cast(size_t)t1b.size(loc);
				size_t tosize = cast(size_t)tob.size(loc);
				if (fromsize != tosize)
				{
					error("cannot cast from %s to %s", e1.type.toChars(), to.toChars());
					return new ErrorExp();
				}
			}
		}
		else if (!to)
		{	
			error("cannot cast tuple");
			to = Type.terror;
		}

//static if (true) {
		if (sc.func && sc.func.isSafe() && !sc.intypeof)
//} else {
//		if (global.params.safe && !sc.module_.safe && !sc.intypeof)
//}
		{	// Disallow unsafe casts
			Type tob = to.toBasetype();
			Type t1b = e1.type.toBasetype();
			if (!t1b.isMutable() && tob.isMutable())
			{   // Cast not mutable to mutable
			  Lunsafe:
				error("cast from %s to %s not allowed in safe code", e1.type.toChars(), to.toChars());
			}
			else if (t1b.isShared() && !tob.isShared())
				// Cast away shared
				goto Lunsafe;
			else if (tob.ty == TY.Tpointer)
			{   if (t1b.ty != TY.Tpointer)
				goto Lunsafe;
				Type tobn = tob.nextOf().toBasetype();
				Type t1bn = t1b.nextOf().toBasetype();

				if (!t1bn.isMutable() && tobn.isMutable())
					// Cast away pointer to not mutable
					goto Lunsafe;

				if (t1bn.isShared() && !tobn.isShared())
					// Cast away pointer to shared
					goto Lunsafe;

        	    if (t1bn.isWild() && !tobn.isConst() && !tobn.isWild())
            		// Cast wild to anything but const | wild
		            goto Lunsafe;

				if (tobn.isTypeBasic() && tobn.size() < t1bn.size()) {
					// Allow things like casting a long* to an int*
					;
				} else if (tobn.ty != TY.Tvoid) {
					// Cast to a pointer other than void*
					goto Lunsafe;
				}
			}

			// BUG: Check for casting array types, such as void[] to int*[]
		}

		e = e1.castTo(sc, to);
		return e;
	}

	override MATCH implicitConvTo(Type t)
	{
	static if (false) {
		printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", toChars(), type.toChars(), t.toChars());
	}
		MATCH result = type.implicitConvTo(t);

		if (result == MATCHnomatch)
		{
			if (t.isintegral() &&
				e1.type.isintegral() &&
				e1.implicitConvTo(t) != MATCHnomatch)
				result = MATCHconvert;
			else
				result = Expression.implicitConvTo(t);
		}
		return result;
	}

	override IntRange getIntRange()
	{
		IntRange ir;
		ir = e1.getIntRange();
		// Do sign extension
		switch (e1.type.toBasetype().ty)
		{
		case Tint8:
			if (ir.imax & 0x80)
			ir.imax |= 0xFFFFFFFFFFFFFF00UL;
			break;
		case Tint16:
			if (ir.imax & 0x8000)
			ir.imax |= 0xFFFFFFFFFFFF0000UL;
			break;
		case Tint32:
			if (ir.imax & 0x80000000)
			ir.imax |= 0xFFFFFFFF00000000UL;
			break;
		default:
		}
		
		if (type.isintegral())
		{
			ir.imin &= type.sizemask();
			ir.imax &= type.sizemask();
		}

		//printf("CastExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax);
		return ir;
	}

	override Expression optimize(int result)
	{
		//printf("CastExp.optimize(result = %d) %s\n", result, toChars());
		//printf("from %s to %s\n", type.toChars(), to.toChars());
		//printf("from %s\n", type.toChars());
		//printf("e1.type %s\n", e1.type.toChars());
		//printf("type = %p\n", type);
		assert(type);
		TOK op1 = e1.op;

		Expression e1old = e1;
		e1 = e1.optimize(result);
		e1 = fromConstInitializer(result, e1);

		if (e1 == e1old &&
		e1.op == TOK.TOKarrayliteral &&
		type.toBasetype().ty == TY.Tpointer &&
		e1.type.toBasetype().ty != TY.Tsarray)
		{
		// Casting this will result in the same expression, and
		// infinite loop because of Expression.implicitCastTo()
		return this;		// no change
		}

		if ((e1.op == TOK.TOKstring || e1.op == TOK.TOKarrayliteral) &&
		(type.ty == TY.Tpointer || type.ty == TY.Tarray) &&
		e1.type.nextOf().size() == type.nextOf().size()
		   )
		{
		Expression e = e1.castTo(null, type);

static if (false) {
		printf(" returning1 %s\n", e.toChars());
}
		return e;
		}

		if (e1.op == TOK.TOKstructliteral &&
		e1.type.implicitConvTo(type) >= MATCH.MATCHconst)
		{
		e1.type = type;
static if (false) {
		printf(" returning2 %s\n", e1.toChars());
}
		return e1;
		}

		/* The first test here is to prevent infinite loops
		 */
		if (op1 != TOK.TOKarrayliteral && e1.op == TOK.TOKarrayliteral)
		return e1.castTo(null, to);
		if (e1.op == TOK.TOKnull &&
		(type.ty == TY.Tpointer || type.ty == TY.Tclass || type.ty == TY.Tarray))
		{
		e1.type = type;
static if (false) {
		printf(" returning3 %s\n", e1.toChars());
}
		return e1;
		}

		if (result & WANT.WANTflags && type.ty == TY.Tclass && e1.type.ty == TY.Tclass)
		{
		// See if we can remove an unnecessary cast
		ClassDeclaration cdfrom;
		ClassDeclaration cdto;
		int offset;

		cdfrom = e1.type.isClassHandle();
		cdto   = type.isClassHandle();
		if (cdto.isBaseOf(cdfrom, &offset) && offset == 0)
		{
			e1.type = type;
static if (false) {
			printf(" returning4 %s\n", e1.toChars());
}
			return e1;
		}
		}

		// We can convert 'head const' to mutable
		if (to.constOf().equals(e1.type.constOf()))
	//    if (to.constConv(e1.type) >= MATCHconst)
		{
		e1.type = type;
static if (false) {
		printf(" returning5 %s\n", e1.toChars());
}
		return e1;
		}

		Expression e;

		if (e1.isConst())
		{
		if (e1.op == TOK.TOKsymoff)
		{
			if (type.size() == e1.type.size() &&
			type.toBasetype().ty != TY.Tsarray)
			{
			e1.type = type;
			return e1;
			}
			return this;
		}
		if (to.toBasetype().ty == TY.Tvoid)
			e = this;
		else
			e = Cast(type, to, e1);
		}
		else
		e = this;
static if (false) {
		printf(" returning6 %s\n", e.toChars());
}
		return e;
	}

	override Expression interpret(InterState istate)
	{
		Expression e;
		Expression e1;

version (LOG) {
		printf("CastExp.interpret() %.*s\n", toChars());
}
		e1 = this.e1.interpret(istate);
		if (e1 is EXP_CANT_INTERPRET)
			goto Lcant;
		return Cast(type, to, e1);

	Lcant:
version (LOG) {
		printf("CastExp.interpret() %.*s CANT\n", toChars());
}
		return EXP_CANT_INTERPRET;
	}

	override bool checkSideEffect(int flag)
	{
		/* if not:
		 *  cast(void)
		 *  cast(classtype)func()
		 */
		if (!to.equals(Type.tvoid) && !(to.ty == Tclass && e1.op == TOKcall && e1.type.ty == Tclass))
			return Expression.checkSideEffect(flag);
			
		return true;
	}

	override void checkEscape()
	{
		Type tb = type.toBasetype();
		if (tb.ty == TY.Tarray && e1.op == TOK.TOKvar && e1.type.toBasetype().ty ==TY.Tsarray)
		{	
			VarExp ve = cast(VarExp)e1;
			VarDeclaration v = ve.var.isVarDeclaration();
			if (v)
			{
				if (!v.isDataseg() && !v.isParameter())
					error("escaping reference to local %s", v.toChars());
			}
		}
	}

	override void toCBuffer(OutBuffer buf, HdrGenState* hgs)
	{
		buf.writestring("cast(");
	version (DMDV1) {
		to.toCBuffer(buf, null, hgs);
	} else {
		if (to)
			to.toCBuffer(buf, null, hgs);
		else
		{
			MODtoBuffer(buf, mod);
		}
	}
		buf.writeByte(')');
		expToCBuffer(buf, hgs, e1, precedence[op]);
	}

	override void buildArrayIdent(OutBuffer buf, Expressions arguments)
	{
		Type tb = type.toBasetype();
		if (tb.ty == Tarray || tb.ty == Tsarray)
		{
			e1.buildArrayIdent(buf, arguments);
		}
		else
			Expression.buildArrayIdent(buf, arguments);
	}

	override Expression buildArrayLoop(Parameters fparams)
	{
		Type tb = type.toBasetype();
		if (tb.ty == Tarray || tb.ty == Tsarray)
		{
			return e1.buildArrayLoop(fparams);
		}
		else
			return Expression.buildArrayLoop(fparams);
	}
	
	static int X(int fty, int tty) {
		return ((fty) * TY.TMAX + (tty));
	}

	override elem* toElem(IRState* irs)
	{
		TY fty;
		TY tty;
		tym_t ftym;
		tym_t ttym;
		OPER eop;

static if (false)
{
		printf("CastExp::toElem()\n");
		print();
		printf("\tfrom: %s\n", e1.type.toChars());
		printf("\tto  : %s\n", to.toChars());
}

		elem* e = e1.toElem(irs);
		Type tfrom = e1.type.toBasetype();
		Type t = to.toBasetype();		// skip over typedef's
		if (t.equals(tfrom))
			goto Lret;

		fty = tfrom.ty;
		//printf("fty = %d\n", fty);
		tty = t.ty;

		if (tty == TY.Tpointer && fty == TY.Tarray
///static if (false) {
///		&& (t.next.ty == Tvoid || t.next.equals(e1.type.next))
///}
		   )
		{
			if (e.Eoper == OPER.OPvar)
			{
				// e1 . *(&e1 + 4)
				e = el_una(OPER.OPaddr, TYM.TYnptr, e);
				e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, 4));
				e = el_una(OPER.OPind, t.totym(),e);
			}
			else
			{
				// e1 . (unsigned)(e1 >> 32)
				e = el_bin(OPER.OPshr, TYM.TYullong, e, el_long(TYM.TYint, 32));
				e = el_una(OPER.OP64_32, t.totym(), e);
			}
			goto Lret;
		}

		if (tty == TY.Tpointer && fty == TY.Tsarray
///static if (false) {
///		&& (t.next.ty == Tvoid || t.next.equals(e1.type.next))
///}
		)
		{
			// e1 . &e1
			e = el_una(OPER.OPaddr, TYM.TYnptr, e);
			goto Lret;
		}

		// Convert from static array to dynamic array
		if (tty == TY.Tarray && fty == TY.Tsarray)
		{
			e = sarray_toDarray(loc, tfrom, t, e);
			goto Lret;
		}

		// Convert from dynamic array to dynamic array
		if (tty == TY.Tarray && fty == TY.Tarray)
		{
			uint fsize = cast(uint)tfrom.nextOf().size();
			uint tsize = cast(uint)t.nextOf().size();

			if (fsize != tsize)
			{
				elem* ep = el_params(e, el_long(TYM.TYint, fsize), el_long(TYM.TYint, tsize), null);
				e = el_bin(OPER.OPcall, type.totym(), el_var(rtlsym[RTLSYM.RTLSYM_ARRAYCAST]), ep);
			}
			goto Lret;
		}

static if (false)
{
		// Convert from dynamic array string literal to static array
		if (tty == TY.Tsarray && fty == TY.Tarray && e1.op == TOK.TOKstring)
		{
			goto Lret;	// treat as a 'paint'
		}
}

		// Casting from base class to derived class requires a runtime check
		if (fty == TY.Tclass && tty == TY.Tclass)
		{
			// Casting from derived class to base class is a no-op
			ClassDeclaration cdfrom;
			ClassDeclaration cdto;
			int offset;
			int rtl = RTLSYM.RTLSYM_DYNAMIC_CAST;

			cdfrom = tfrom.isClassHandle();
			cdto   = t.isClassHandle();
			if (cdfrom.isInterfaceDeclaration())
			{
				rtl = RTLSYM.RTLSYM_INTERFACE_CAST;
				if (cdfrom.isCPPinterface())
				{
					if (cdto.isCPPinterface())
					{
						/* Casting from a C++ interface to a C++ interface
						 * is always a 'paint' operation
						 */
						goto Lret;			// no-op
					}

					/* Casting from a C++ interface to a class
					 * always results in null because there is no runtime
					 * information available to do it.
					 *
					 * Casting from a C++ interface to a non-C++ interface
					 * always results in null because there's no way one
					 * can be derived from the other.
					 */
					e = el_bin(OPER.OPcomma, TYM.TYnptr, e, el_long(TYM.TYnptr, 0));
					goto Lret;
				}
			}
			if (cdto.isBaseOf(cdfrom, &offset) && offset != OFFSET_RUNTIME)
			{
				/* The offset from cdfrom=>cdto is known at compile time.
				 */
			
				//printf("offset = %d\n", offset);
				if (offset)
				{
					/* Rewrite cast as (e ? e + offset : null)
					 */
					elem* etmp;
					elem* ex;

					if (e1.op == TOK.TOKthis)
					{   
						// Assume 'this' is never null, so skip null check
						e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, offset));
					}
					else
					{
						etmp = el_same(&e);
						ex = el_bin(OPER.OPadd, TYM.TYnptr, etmp, el_long(TYM.TYint, offset));
						ex = el_bin(OPER.OPcolon, TYM.TYnptr, ex, el_long(TYM.TYnptr, 0));
						e = el_bin(OPER.OPcond, TYM.TYnptr, e, ex);
					}
				}
				goto Lret;			// no-op
			}

			/* The offset from cdfrom=>cdto can only be determined at runtime.
			 */
			elem* ep;

			ep = el_param(el_ptr(cdto.toSymbol()), e);
			e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[rtl]), ep);
			goto Lret;
		}

		ftym = tybasic(e.Ety);
		ttym = tybasic(t.totym());
		if (ftym == ttym)
		goto Lret;

		switch (tty)
		{
			case TY.Tpointer:
				if (fty == TY.Tdelegate)
					goto Lpaint;
				tty = TY.Tuns32;
				break;

			case TY.Tchar:
				tty = TY.Tuns8;	
				break;
			case TY.Twchar:
				tty = TY.Tuns16;	
				break;
			case TY.Tdchar:	
				tty = TY.Tuns32;	
				break;
			case TY.Tvoid:	
				goto Lpaint;

			case TY.Tbool:
			{
				// Construct e?true:false
				elem* eq;

				e = el_una(OPER.OPbool, ttym, e);
				goto Lret;
			}
			
			default:
				break;	///
		}

		switch (fty)
		{
			case TY.Tpointer:	fty = TY.Tuns32;	break;
			case TY.Tchar:		fty = TY.Tuns8;		break;
			case TY.Twchar:		fty = TY.Tuns16;	break;
			case TY.Tdchar:		fty = TY.Tuns32;	break;
			default:	break;	///
		}

	Lagain:
		switch (X(fty,tty))
		{
static if (false)
{
			case X(TY.Tbit,TY.Tint8):
			case X(TY.Tbit,TY.Tuns8):
				goto Lpaint;
			case X(TY.Tbit,TY.Tint16):
			case X(TY.Tbit,TY.Tuns16):
			case X(TY.Tbit,TY.Tint32):
			case X(TY.Tbit,TY.Tuns32):	
				eop = OPu8_16;
				goto Leop;
			case X(TY.Tbit,TY.Tint64):
			case X(TY.Tbit,TY.Tuns64):
			case X(TY.Tbit,TY.Tfloat32):
			case X(TY.Tbit,TY.Tfloat64):
			case X(TY.Tbit,TY.Tfloat80):
			case X(TY.Tbit,TY.Tcomplex32):
			case X(TY.Tbit,TY.Tcomplex64):
			case X(TY.Tbit,TY.Tcomplex80):
				e = el_una(OPER.OPu8_16, TYM.TYuint, e);
				fty = TY.Tuns32;
				goto Lagain;
			case X(Tbit,Timaginary32):
			case X(Tbit,Timaginary64):
			case X(Tbit,Timaginary80):
				goto Lzero;
}
		/* ============================= */

		case X(TY.Tbool,TY.Tint8):
		case X(TY.Tbool,TY.Tuns8):
			goto Lpaint;
		case X(TY.Tbool,TY.Tint16):
		case X(TY.Tbool,TY.Tuns16):
		case X(TY.Tbool,TY.Tint32):
		case X(TY.Tbool,TY.Tuns32):
			eop = OPER.OPu8_16;
			goto Leop;
		case X(TY.Tbool,TY.Tint64):
		case X(TY.Tbool,TY.Tuns64):
		case X(TY.Tbool,TY.Tfloat32):
		case X(TY.Tbool,TY.Tfloat64):
		case X(TY.Tbool,TY.Tfloat80):
		case X(TY.Tbool,TY.Tcomplex32):
		case X(TY.Tbool,TY.Tcomplex64):
		case X(TY.Tbool,TY.Tcomplex80):
			e = el_una(OPER.OPu8_16, TYM.TYuint, e);
			fty = TY.Tuns32;
			goto Lagain;
		case X(TY.Tbool,TY.Timaginary32):
		case X(TY.Tbool,TY.Timaginary64):
		case X(TY.Tbool,TY.Timaginary80):
			goto Lzero;

		/* ============================= */

		case X(TY.Tint8,TY.Tuns8):
			goto Lpaint;
		case X(TY.Tint8,TY.Tint16):
		case X(TY.Tint8,TY.Tuns16):
		case X(TY.Tint8,TY.Tint32):
		case X(TY.Tint8,TY.Tuns32):
			eop = OPER.OPs8_16;
			goto Leop;
		case X(TY.Tint8,TY.Tint64):
		case X(TY.Tint8,TY.Tuns64):
		case X(TY.Tint8,TY.Tfloat32):
		case X(TY.Tint8,TY.Tfloat64):
		case X(TY.Tint8,TY.Tfloat80):
		case X(TY.Tint8,TY.Tcomplex32):
		case X(TY.Tint8,TY.Tcomplex64):
		case X(TY.Tint8,TY.Tcomplex80):
			e = el_una(OPER.OPs8_16, TYM.TYint, e);
			fty = TY.Tint32;
			goto Lagain;
		case X(TY.Tint8,TY.Timaginary32):
		case X(TY.Tint8,TY.Timaginary64):
		case X(TY.Tint8,TY.Timaginary80):
			goto Lzero;

		/* ============================= */

		case X(TY.Tuns8,TY.Tint8):
			goto Lpaint;
		case X(TY.Tuns8,TY.Tint16):
		case X(TY.Tuns8,TY.Tuns16):
		case X(TY.Tuns8,TY.Tint32):
		case X(TY.Tuns8,TY.Tuns32):
			eop = OPER.OPu8_16;
			goto Leop;
		case X(TY.Tuns8,TY.Tint64):
		case X(TY.Tuns8,TY.Tuns64):
		case X(TY.Tuns8,TY.Tfloat32):
		case X(TY.Tuns8,TY.Tfloat64):
		case X(TY.Tuns8,TY.Tfloat80):
		case X(TY.Tuns8,TY.Tcomplex32):
		case X(TY.Tuns8,TY.Tcomplex64):
		case X(TY.Tuns8,TY.Tcomplex80):
			e = el_una(OPER.OPu8_16, TYM.TYuint, e);
			fty = TY.Tuns32;
			goto Lagain;
		case X(TY.Tuns8,TY.Timaginary32):
		case X(TY.Tuns8,TY.Timaginary64):
		case X(TY.Tuns8,TY.Timaginary80):
			goto Lzero;

		/* ============================= */

		case X(TY.Tint16,TY.Tint8):
		case X(TY.Tint16,TY.Tuns8):
			eop = OPER.OP16_8;
			goto Leop;
		case X(TY.Tint16,TY.Tuns16):
			goto Lpaint;
		case X(TY.Tint16,TY.Tint32):
		case X(TY.Tint16,TY.Tuns32):
			eop = OPER.OPs16_32;
			goto Leop;
		case X(TY.Tint16,TY.Tint64):
		case X(TY.Tint16,TY.Tuns64):
			e = el_una(OPER.OPs16_32, TYM.TYint, e);
			fty = TY.Tint32;
			goto Lagain;
		case X(TY.Tint16,TY.Tfloat32):
		case X(TY.Tint16,TY.Tfloat64):
		case X(TY.Tint16,TY.Tfloat80):
		case X(TY.Tint16,TY.Tcomplex32):
		case X(TY.Tint16,TY.Tcomplex64):
		case X(TY.Tint16,TY.Tcomplex80):
			e = el_una(OPER.OPs16_d, TYM.TYdouble, e);
			fty = TY.Tfloat64;
			goto Lagain;
		case X(TY.Tint16,TY.Timaginary32):
		case X(TY.Tint16,TY.Timaginary64):
		case X(TY.Tint16,TY.Timaginary80):
			goto Lzero;

		/* ============================= */

		case X(TY.Tuns16,TY.Tint8):
		case X(TY.Tuns16,TY.Tuns8):
			eop = OPER.OP16_8;
			goto Leop;
		case X(TY.Tuns16,TY.Tint16):
			goto Lpaint;
		case X(TY.Tuns16,TY.Tint32):
		case X(TY.Tuns16,TY.Tuns32):
			eop = OPER.OPu16_32;
			goto Leop;
		case X(TY.Tuns16,TY.Tint64):
		case X(TY.Tuns16,TY.Tuns64):
		case X(TY.Tuns16,TY.Tfloat64):
		case X(TY.Tuns16,TY.Tfloat32):
		case X(TY.Tuns16,TY.Tfloat80):
		case X(TY.Tuns16,TY.Tcomplex32):
		case X(TY.Tuns16,TY.Tcomplex64):
		case X(TY.Tuns16,TY.Tcomplex80):
			e = el_una(OPER.OPu16_32, TYM.TYuint, e);
			fty = TY.Tuns32;
			goto Lagain;
		case X(TY.Tuns16,TY.Timaginary32):
		case X(TY.Tuns16,TY.Timaginary64):
		case X(TY.Tuns16,TY.Timaginary80):
			goto Lzero;

		/* ============================= */

		case X(TY.Tint32,TY.Tint8):
		case X(TY.Tint32,TY.Tuns8):	
			e = el_una(OPER.OP32_16, TYM.TYshort, e);
			fty = TY.Tint16;
			goto Lagain;
		case X(TY.Tint32,TY.Tint16):
		case X(TY.Tint32,TY.Tuns16):
			eop = OPER.OP32_16;
			goto Leop;
		case X(TY.Tint32,TY.Tuns32):
			goto Lpaint;
		case X(TY.Tint32,TY.Tint64):
		case X(TY.Tint32,TY.Tuns64):
			eop = OPER.OPs32_64;
			goto Leop;
		case X(TY.Tint32,TY.Tfloat32):
		case X(TY.Tint32,TY.Tfloat64):
		case X(TY.Tint32,TY.Tfloat80):
		case X(TY.Tint32,TY.Tcomplex32):
		case X(TY.Tint32,TY.Tcomplex64):
		case X(TY.Tint32,TY.Tcomplex80):
			e = el_una(OPER.OPs32_d, TYM.TYdouble, e);
			fty = TY.Tfloat64;
			goto Lagain;
		case X(TY.Tint32,TY.Timaginary32):
		case X(TY.Tint32,TY.Timaginary64):
		case X(TY.Tint32,TY.Timaginary80):
			goto Lzero;

		/* ============================= */

		case X(TY.Tuns32,TY.Tint8):
		case X(TY.Tuns32,TY.Tuns8):
			e = el_una(OPER.OP32_16, TYM.TYshort, e);
			fty = TY.Tuns16;
			goto Lagain;
		case X(TY.Tuns32,TY.Tint16):
		case X(TY.Tuns32,TY.Tuns16):
			eop = OPER.OP32_16;
			goto Leop;
		case X(TY.Tuns32,TY.Tint32):
			goto Lpaint;
		case X(TY.Tuns32,TY.Tint64):
		case X(TY.Tuns32,TY.Tuns64):
			eop = OPER.OPu32_64;
			goto Leop;
		case X(TY.Tuns32,TY.Tfloat32):
		case X(TY.Tuns32,TY.Tfloat64):
		case X(TY.Tuns32,TY.Tfloat80):
		case X(TY.Tuns32,TY.Tcomplex32):
		case X(TY.Tuns32,TY.Tcomplex64):
		case X(TY.Tuns32,TY.Tcomplex80):
			e = el_una(OPER.OPu32_d, TYM.TYdouble, e);
			fty = TY.Tfloat64;
			goto Lagain;
		case X(TY.Tuns32,TY.Timaginary32):
		case X(TY.Tuns32,TY.Timaginary64):
		case X(TY.Tuns32,TY.Timaginary80):
			goto Lzero;

		/* ============================= */

		case X(TY.Tint64,TY.Tint8):
		case X(TY.Tint64,TY.Tuns8):
		case X(TY.Tint64,TY.Tint16):
		case X(TY.Tint64,TY.Tuns16):
			e = el_una(OPER.OP64_32, TYM.TYint, e);
			fty = TY.Tint32;
			goto Lagain;
		case X(TY.Tint64,TY.Tint32):
		case X(TY.Tint64,TY.Tuns32):
			eop = OPER.OP64_32;
			goto Leop;
		case X(TY.Tint64,TY.Tuns64):
			goto Lpaint;
		case X(TY.Tint64,TY.Tfloat32):
		case X(TY.Tint64,TY.Tfloat64):
		case X(TY.Tint64,TY.Tfloat80):
		case X(TY.Tint64,TY.Tcomplex32):
		case X(TY.Tint64,TY.Tcomplex64):
		case X(TY.Tint64,TY.Tcomplex80):
			e = el_una(OPER.OPs64_d, TYM.TYdouble, e);
			fty = TY.Tfloat64;
			goto Lagain;
		case X(TY.Tint64,TY.Timaginary32):
		case X(TY.Tint64,TY.Timaginary64):
		case X(TY.Tint64,TY.Timaginary80):
			goto Lzero;

		/* ============================= */

		case X(TY.Tuns64,TY.Tint8):
		case X(TY.Tuns64,TY.Tuns8):
		case X(TY.Tuns64,TY.Tint16):
		case X(TY.Tuns64,TY.Tuns16):
			e = el_una(OPER.OP64_32, TYM.TYint, e);
			fty = TY.Tint32;
			goto Lagain;
		case X(TY.Tuns64,TY.Tint32):
		case X(TY.Tuns64,TY.Tuns32):
			eop = OPER.OP64_32;
			goto Leop;
		case X(TY.Tuns64,TY.Tint64):
			goto Lpaint;
		case X(TY.Tuns64,TY.Tfloat32):
		case X(TY.Tuns64,TY.Tfloat64):
		case X(TY.Tuns64,TY.Tfloat80):
		case X(TY.Tuns64,TY.Tcomplex32):
		case X(TY.Tuns64,TY.Tcomplex64):
		case X(TY.Tuns64,TY.Tcomplex80):
			 e = el_una(OPER.OPu64_d, TYM.TYdouble, e);
			 fty = TY.Tfloat64;
			 goto Lagain;
		case X(TY.Tuns64,TY.Timaginary32):
		case X(TY.Tuns64,TY.Timaginary64):
		case X(TY.Tuns64,TY.Timaginary80):
			goto Lzero;

		/* ============================= */

		case X(TY.Tfloat32,TY.Tint8):
		case X(TY.Tfloat32,TY.Tuns8):
		case X(TY.Tfloat32,TY.Tint16):
		case X(TY.Tfloat32,TY.Tuns16):
		case X(TY.Tfloat32,TY.Tint32):
		case X(TY.Tfloat32,TY.Tuns32):
		case X(TY.Tfloat32,TY.Tint64):
		case X(TY.Tfloat32,TY.Tuns64):
		case X(TY.Tfloat32,TY.Tfloat80):
			e = el_una(OPER.OPf_d, TYM.TYdouble, e);
			fty = TY.Tfloat64;
			goto Lagain;
		case X(TY.Tfloat32,TY.Tfloat64):
			eop = OPER.OPf_d;
			goto Leop;
		case X(TY.Tfloat32,TY.Timaginary32):
			goto Lzero;
		case X(TY.Tfloat32,TY.Timaginary64):
			goto Lzero;
		case X(TY.Tfloat32,TY.Timaginary80):
			goto Lzero;
		case X(TY.Tfloat32,TY.Tcomplex32):
		case X(TY.Tfloat32,TY.Tcomplex64):
		case X(TY.Tfloat32,TY.Tcomplex80):
			e = el_bin(OPER.OPadd,TYM.TYcfloat,el_long(TYM.TYifloat,0),e);
			fty = TY.Tcomplex32;
			goto Lagain;

		/* ============================= */

		case X(TY.Tfloat64,TY.Tint8):
		case X(TY.Tfloat64,TY.Tuns8):
			e = el_una(OPER.OPd_s16, TYM.TYshort, e);
			fty = TY.Tint16;
			goto Lagain;
		case X(TY.Tfloat64,TY.Tint16):  
			eop = OPER.OPd_s16;
			goto Leop;
		case X(TY.Tfloat64,TY.Tuns16):  
			eop = OPER.OPd_u16;
			goto Leop;
		case X(TY.Tfloat64,TY.Tint32):   
			eop = OPER.OPd_s32; 
			goto Leop;
		case X(TY.Tfloat64,TY.Tuns32):   
			eop = OPER.OPd_u32; 
			goto Leop;
		case X(TY.Tfloat64,TY.Tint64):   
			eop = OPER.OPd_s64; 
			goto Leop;
		case X(TY.Tfloat64,TY.Tuns64):   
			eop = OPER.OPd_u64; 
			goto Leop;
		case X(TY.Tfloat64,TY.Tfloat32): 
			eop = OPER.OPd_f;   
			goto Leop;
		case X(TY.Tfloat64,TY.Tfloat80): 
			eop = OPER.OPd_ld;  
			goto Leop;
		case X(TY.Tfloat64,TY.Timaginary32):	
			goto Lzero;
		case X(TY.Tfloat64,TY.Timaginary64):	
			goto Lzero;
		case X(TY.Tfloat64,TY.Timaginary80):	
			goto Lzero;
		case X(TY.Tfloat64,TY.Tcomplex32):
		case X(TY.Tfloat64,TY.Tcomplex64):
		case X(TY.Tfloat64,TY.Tcomplex80):
			e = el_bin(OPER.OPadd,TYM.TYcfloat,el_long(TYM.TYidouble,0),e);
			fty = TY.Tcomplex64;
			goto Lagain;

		/* ============================= */

		case X(TY.Tfloat80,TY.Tint8):
		case X(TY.Tfloat80,TY.Tuns8):
		case X(TY.Tfloat80,TY.Tint16):
		case X(TY.Tfloat80,TY.Tuns16):
		case X(TY.Tfloat80,TY.Tint32):
		case X(TY.Tfloat80,TY.Tuns32):
		case X(TY.Tfloat80,TY.Tint64):
		case X(TY.Tfloat80,TY.Tfloat32):
			e = el_una(OPER.OPld_d, TYM.TYdouble, e);
			fty = TY.Tfloat64;
			goto Lagain;
		case X(TY.Tfloat80,TY.Tuns64):
			eop = OPER.OPld_u64;
			goto Leop;
		case X(TY.Tfloat80,TY.Tfloat64):
			eop = OPER.OPld_d;
			goto Leop;
		case X(TY.Tfloat80,TY.Timaginary32):
			goto Lzero;
		case X(TY.Tfloat80,TY.Timaginary64):
			goto Lzero;
		case X(TY.Tfloat80,TY.Timaginary80):
			goto Lzero;
		case X(TY.Tfloat80,TY.Tcomplex32):
		case X(TY.Tfloat80,TY.Tcomplex64):
		case X(TY.Tfloat80,TY.Tcomplex80):
			e = el_bin(OPER.OPadd,TYM.TYcldouble,e,el_long(TYM.TYildouble,0));
			fty = TY.Tcomplex80;
			goto Lagain;

		/* ============================= */

		case X(TY.Timaginary32,TY.Tint8):
		case X(TY.Timaginary32,TY.Tuns8):
		case X(TY.Timaginary32,TY.Tint16):
		case X(TY.Timaginary32,TY.Tuns16):
		case X(TY.Timaginary32,TY.Tint32):
		case X(TY.Timaginary32,TY.Tuns32):
		case X(TY.Timaginary32,TY.Tint64):
		case X(TY.Timaginary32,TY.Tuns64):
		case X(TY.Timaginary32,TY.Tfloat32):
		case X(TY.Timaginary32,TY.Tfloat64):
		case X(TY.Timaginary32,TY.Tfloat80):
			goto Lzero;
		case X(TY.Timaginary32,TY.Timaginary64):
			eop = OPER.OPf_d;
			goto Leop;
		case X(TY.Timaginary32,TY.Timaginary80):
			e = el_una(OPER.OPf_d, TYM.TYidouble, e);
			fty = TY.Timaginary64;
			goto Lagain;
		case X(TY.Timaginary32,TY.Tcomplex32):
		case X(TY.Timaginary32,TY.Tcomplex64):
		case X(TY.Timaginary32,TY.Tcomplex80):
			e = el_bin(OPER.OPadd,TYM.TYcfloat,el_long(TYM.TYfloat,0),e);
			fty = TY.Tcomplex32;
			goto Lagain;

		/* ============================= */

		case X(TY.Timaginary64,TY.Tint8):
		case X(TY.Timaginary64,TY.Tuns8):
		case X(TY.Timaginary64,TY.Tint16):
		case X(TY.Timaginary64,TY.Tuns16):
		case X(TY.Timaginary64,TY.Tint32):
		case X(TY.Timaginary64,TY.Tuns32):
		case X(TY.Timaginary64,TY.Tint64):
		case X(TY.Timaginary64,TY.Tuns64):
		case X(TY.Timaginary64,TY.Tfloat32):
		case X(TY.Timaginary64,TY.Tfloat64):
		case X(TY.Timaginary64,TY.Tfloat80):
			goto Lzero;
		case X(TY.Timaginary64,TY.Timaginary32):
			eop = OPER.OPd_f;  
			goto Leop;
		case X(TY.Timaginary64,TY.Timaginary80):
			eop = OPER.OPd_ld; 
			goto Leop;
		case X(TY.Timaginary64,TY.Tcomplex32):
		case X(TY.Timaginary64,TY.Tcomplex64):
		case X(TY.Timaginary64,TY.Tcomplex80):
			e = el_bin(OPER.OPadd, TYM.TYcdouble, el_long(TYM.TYdouble,0), e);
			fty = TY.Tcomplex64;
			goto Lagain;

		/* ============================= */

		case X(TY.Timaginary80,TY.Tint8):
		case X(TY.Timaginary80,TY.Tuns8):
		case X(TY.Timaginary80,TY.Tint16):
		case X(TY.Timaginary80,TY.Tuns16):
		case X(TY.Timaginary80,TY.Tint32):
		case X(TY.Timaginary80,TY.Tuns32):
		case X(TY.Timaginary80,TY.Tint64):
		case X(TY.Timaginary80,TY.Tuns64):
		case X(TY.Timaginary80,TY.Tfloat32):
		case X(TY.Timaginary80,TY.Tfloat64):
		case X(TY.Timaginary80,TY.Tfloat80):
			goto Lzero;
		case X(TY.Timaginary80,TY.Timaginary32):
			e = el_una(OPER.OPf_d, TYM.TYidouble, e);
			fty = TY.Timaginary64;
			goto Lagain;
		case X(TY.Timaginary80,TY.Timaginary64):
			eop = OPER.OPld_d;
			goto Leop;
		case X(TY.Timaginary80,TY.Tcomplex32):
		case X(TY.Timaginary80,TY.Tcomplex64):
		case X(TY.Timaginary80,TY.Tcomplex80):
			e = el_bin(OPER.OPadd, TYM.TYcldouble, el_long(TYM.TYldouble,0), e);
			fty = TY.Tcomplex80;
			goto Lagain;

		/* ============================= */

		case X(TY.Tcomplex32,TY.Tint8):
		case X(TY.Tcomplex32,TY.Tuns8):
		case X(TY.Tcomplex32,TY.Tint16):
		case X(TY.Tcomplex32,TY.Tuns16):
		case X(TY.Tcomplex32,TY.Tint32):
		case X(TY.Tcomplex32,TY.Tuns32):
		case X(TY.Tcomplex32,TY.Tint64):
		case X(TY.Tcomplex32,TY.Tuns64):
		case X(TY.Tcomplex32,TY.Tfloat32):
		case X(TY.Tcomplex32,TY.Tfloat64):
		case X(TY.Tcomplex32,TY.Tfloat80):
			e = el_una(OPER.OPc_r, TYM.TYfloat, e);
			fty = TY.Tfloat32;
			goto Lagain;
		case X(TY.Tcomplex32,TY.Timaginary32):
		case X(TY.Tcomplex32,TY.Timaginary64):
		case X(TY.Tcomplex32,TY.Timaginary80):
			e = el_una(OPER.OPc_i, TYM.TYifloat, e);
			fty = TY.Timaginary32;
			goto Lagain;
		case X(TY.Tcomplex32,TY.Tcomplex64):
		case X(TY.Tcomplex32,TY.Tcomplex80):
			e = el_una(OPER.OPf_d, TYM.TYcdouble, e);
			fty = TY.Tcomplex64;
			goto Lagain;

		/* ============================= */

		case X(TY.Tcomplex64,TY.Tint8):
		case X(TY.Tcomplex64,TY.Tuns8):
		case X(TY.Tcomplex64,TY.Tint16):
		case X(TY.Tcomplex64,TY.Tuns16):
		case X(TY.Tcomplex64,TY.Tint32):
		case X(TY.Tcomplex64,TY.Tuns32):
		case X(TY.Tcomplex64,TY.Tint64):
		case X(TY.Tcomplex64,TY.Tuns64):
		case X(TY.Tcomplex64,TY.Tfloat32):
		case X(TY.Tcomplex64,TY.Tfloat64):
		case X(TY.Tcomplex64,TY.Tfloat80):
			e = el_una(OPER.OPc_r, TYM.TYdouble, e);
			fty = TY.Tfloat64;
			goto Lagain;
		case X(TY.Tcomplex64,TY.Timaginary32):
		case X(TY.Tcomplex64,TY.Timaginary64):
		case X(TY.Tcomplex64,TY.Timaginary80):
			e = el_una(OPER.OPc_i, TYM.TYidouble, e);
			fty = TY.Timaginary64;
			goto Lagain;
		case X(TY.Tcomplex64,TY.Tcomplex32):
			eop = OPER.OPd_f;
			goto Leop;
		case X(TY.Tcomplex64,TY.Tcomplex80):
			eop = OPER.OPd_ld;
			goto Leop;

		/* ============================= */

		case X(TY.Tcomplex80,TY.Tint8):
		case X(TY.Tcomplex80,TY.Tuns8):
		case X(TY.Tcomplex80,TY.Tint16):
		case X(TY.Tcomplex80,TY.Tuns16):
		case X(TY.Tcomplex80,TY.Tint32):
		case X(TY.Tcomplex80,TY.Tuns32):
		case X(TY.Tcomplex80,TY.Tint64):
		case X(TY.Tcomplex80,TY.Tuns64):
		case X(TY.Tcomplex80,TY.Tfloat32):
		case X(TY.Tcomplex80,TY.Tfloat64):
		case X(TY.Tcomplex80,TY.Tfloat80):
			e = el_una(OPER.OPc_r, TYM.TYldouble, e);
			fty = TY.Tfloat80;
			goto Lagain;
		case X(TY.Tcomplex80,TY.Timaginary32):
		case X(TY.Tcomplex80,TY.Timaginary64):
		case X(TY.Tcomplex80,TY.Timaginary80):
			e = el_una(OPER.OPc_i, TYM.TYildouble, e);
			fty = TY.Timaginary80;
			goto Lagain;
		case X(TY.Tcomplex80,TY.Tcomplex32):
		case X(TY.Tcomplex80,TY.Tcomplex64):
			e = el_una(OPER.OPld_d, TYM.TYcdouble, e);
			fty = TY.Tcomplex64;
			goto Lagain;

		/* ============================= */

		default:
			if (fty == tty)
				goto Lpaint;
			//dump(0);
			//writef("fty = %d, tty = %d, %d\n", fty, tty, t.ty);
			error("e2ir: cannot cast %s of type %s to type %s", e1.toChars(), e1.type.toChars(), t.toChars());
			goto Lzero;

		Lzero:
			e = el_long(ttym, 0);
			break;

		Lpaint:
			e.Ety = ttym;
			break;

		Leop:
			e = el_una(eop, ttym, e);
			break;
		}
	Lret:
		// Adjust for any type paints
		t = type.toBasetype();
		e.Ety = t.totym();

		el_setLoc(e,loc);
		return e;
	}

	override Identifier opId()
	{
		return Id.cast_;
	}
}