2016-12-10 16:23:07 -08:00
|
|
|
use rustc::ty::{self, Ty};
|
|
|
|
use syntax::ast::{FloatTy, IntTy, UintTy};
|
2016-09-07 18:34:59 +02:00
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
use super::{PrimVal, EvalContext, EvalResult, MemoryPointer, PointerArithmetic, Machine};
|
2016-09-07 18:34:59 +02:00
|
|
|
|
2017-07-21 17:25:30 +02:00
|
|
|
impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
2016-11-26 22:58:01 -08:00
|
|
|
pub(super) fn cast_primval(
|
|
|
|
&self,
|
|
|
|
val: PrimVal,
|
|
|
|
src_ty: Ty<'tcx>,
|
2017-08-10 08:48:38 -07:00
|
|
|
dest_ty: Ty<'tcx>,
|
2016-11-26 22:58:01 -08:00
|
|
|
) -> EvalResult<'tcx, PrimVal> {
|
2017-08-25 16:20:13 +02:00
|
|
|
trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
|
2017-07-20 13:52:58 -07:00
|
|
|
let src_kind = self.ty_to_primval_kind(src_ty)?;
|
2016-11-26 22:58:01 -08:00
|
|
|
|
2017-07-20 14:03:02 -07:00
|
|
|
match val {
|
|
|
|
PrimVal::Undef => Ok(PrimVal::Undef),
|
|
|
|
PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
|
|
|
|
val @ PrimVal::Bytes(_) => {
|
2017-07-21 13:39:06 +02:00
|
|
|
use super::PrimValKind::*;
|
2017-07-20 14:03:02 -07:00
|
|
|
match src_kind {
|
|
|
|
F32 => self.cast_from_float(val.to_f32()? as f64, dest_ty),
|
|
|
|
F64 => self.cast_from_float(val.to_f64()?, dest_ty),
|
|
|
|
|
|
|
|
I8 | I16 | I32 | I64 | I128 => {
|
|
|
|
self.cast_from_signed_int(val.to_i128()?, dest_ty)
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
2017-07-20 14:03:02 -07:00
|
|
|
|
|
|
|
Bool | Char | U8 | U16 | U32 | U64 | U128 | FnPtr | Ptr => {
|
|
|
|
self.cast_from_int(val.to_u128()?, dest_ty, false)
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
2017-06-22 18:41:10 -07:00
|
|
|
}
|
2017-07-20 14:03:02 -07:00
|
|
|
}
|
2016-09-07 18:34:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-20 14:03:02 -07:00
|
|
|
fn cast_from_signed_int(&self, val: i128, ty: ty::Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
|
|
|
|
self.cast_from_int(val as u128, ty, val < 0)
|
2016-09-07 18:34:59 +02:00
|
|
|
}
|
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
fn cast_from_int(
|
|
|
|
&self,
|
|
|
|
v: u128,
|
|
|
|
ty: ty::Ty<'tcx>,
|
|
|
|
negative: bool,
|
|
|
|
) -> EvalResult<'tcx, PrimVal> {
|
2016-10-20 04:42:19 -06:00
|
|
|
use rustc::ty::TypeVariants::*;
|
2016-09-07 18:34:59 +02:00
|
|
|
match ty.sty {
|
2017-07-19 11:35:06 -07:00
|
|
|
// Casts to bool are not permitted by rustc, no need to handle them here.
|
2017-08-10 08:48:38 -07:00
|
|
|
TyInt(IntTy::I8) => Ok(PrimVal::Bytes(v as i128 as i8 as u128)),
|
2017-01-12 08:28:42 +01:00
|
|
|
TyInt(IntTy::I16) => Ok(PrimVal::Bytes(v as i128 as i16 as u128)),
|
|
|
|
TyInt(IntTy::I32) => Ok(PrimVal::Bytes(v as i128 as i32 as u128)),
|
|
|
|
TyInt(IntTy::I64) => Ok(PrimVal::Bytes(v as i128 as i64 as u128)),
|
|
|
|
TyInt(IntTy::I128) => Ok(PrimVal::Bytes(v as u128)),
|
2016-10-20 04:42:19 -06:00
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
TyUint(UintTy::U8) => Ok(PrimVal::Bytes(v as u8 as u128)),
|
2017-01-12 08:28:42 +01:00
|
|
|
TyUint(UintTy::U16) => Ok(PrimVal::Bytes(v as u16 as u128)),
|
|
|
|
TyUint(UintTy::U32) => Ok(PrimVal::Bytes(v as u32 as u128)),
|
|
|
|
TyUint(UintTy::U64) => Ok(PrimVal::Bytes(v as u64 as u128)),
|
|
|
|
TyUint(UintTy::U128) => Ok(PrimVal::Bytes(v)),
|
2016-10-20 04:42:19 -06:00
|
|
|
|
|
|
|
TyInt(IntTy::Is) => {
|
2016-09-07 18:34:59 +02:00
|
|
|
let int_ty = self.tcx.sess.target.int_type;
|
|
|
|
let ty = self.tcx.mk_mach_int(int_ty);
|
2017-07-20 14:03:02 -07:00
|
|
|
self.cast_from_int(v, ty, negative)
|
2016-10-20 04:42:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
TyUint(UintTy::Us) => {
|
2016-09-07 18:34:59 +02:00
|
|
|
let uint_ty = self.tcx.sess.target.uint_type;
|
|
|
|
let ty = self.tcx.mk_mach_uint(uint_ty);
|
2017-07-20 14:03:02 -07:00
|
|
|
self.cast_from_int(v, ty, negative)
|
2016-10-20 04:42:19 -06:00
|
|
|
}
|
|
|
|
|
2017-01-12 08:28:42 +01:00
|
|
|
TyFloat(FloatTy::F64) if negative => Ok(PrimVal::from_f64(v as i128 as f64)),
|
2017-08-10 08:48:38 -07:00
|
|
|
TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(v as f64)),
|
2017-01-12 08:28:42 +01:00
|
|
|
TyFloat(FloatTy::F32) if negative => Ok(PrimVal::from_f32(v as i128 as f32)),
|
2017-08-10 08:48:38 -07:00
|
|
|
TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(v as f32)),
|
2016-10-20 04:42:19 -06:00
|
|
|
|
2017-01-12 08:28:42 +01:00
|
|
|
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
|
2017-08-02 16:59:01 +02:00
|
|
|
TyChar => err!(InvalidChar(v)),
|
2016-10-20 04:42:19 -06:00
|
|
|
|
2017-07-21 20:02:44 -07:00
|
|
|
// No alignment check needed for raw pointers. But we have to truncate to target ptr size.
|
2017-07-22 11:28:14 -07:00
|
|
|
TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)),
|
2016-10-20 04:42:19 -06:00
|
|
|
|
2017-08-02 16:59:01 +02:00
|
|
|
_ => err!(Unimplemented(format!("int to {:?} cast", ty))),
|
2016-09-07 18:34:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-20 14:03:02 -07:00
|
|
|
fn cast_from_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
|
2016-10-20 04:42:19 -06:00
|
|
|
use rustc::ty::TypeVariants::*;
|
2016-09-07 18:34:59 +02:00
|
|
|
match ty.sty {
|
2016-10-20 04:42:19 -06:00
|
|
|
// Casting negative floats to unsigned integers yields zero.
|
2017-07-20 14:03:02 -07:00
|
|
|
TyUint(_) if val < 0.0 => self.cast_from_int(0, ty, false),
|
2017-08-10 08:48:38 -07:00
|
|
|
TyInt(_) if val < 0.0 => self.cast_from_int(val as i128 as u128, ty, true),
|
2016-10-20 04:42:19 -06:00
|
|
|
|
2017-07-20 14:03:02 -07:00
|
|
|
TyInt(_) | ty::TyUint(_) => self.cast_from_int(val as u128, ty, false),
|
2016-10-20 04:42:19 -06:00
|
|
|
|
|
|
|
TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(val)),
|
|
|
|
TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(val as f32)),
|
2017-08-02 16:59:01 +02:00
|
|
|
_ => err!(Unimplemented(format!("float to {:?} cast", ty))),
|
2016-09-07 18:34:59 +02:00
|
|
|
}
|
|
|
|
}
|
2016-10-20 04:42:19 -06:00
|
|
|
|
2017-07-20 14:03:02 -07:00
|
|
|
fn cast_from_ptr(&self, ptr: MemoryPointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
|
2016-10-20 04:42:19 -06:00
|
|
|
use rustc::ty::TypeVariants::*;
|
|
|
|
match ty.sty {
|
2017-06-22 18:41:10 -07:00
|
|
|
// Casting to a reference or fn pointer is not permitted by rustc, no need to support it here.
|
2017-08-10 08:48:38 -07:00
|
|
|
TyRawPtr(_) |
|
|
|
|
TyInt(IntTy::Is) |
|
|
|
|
TyUint(UintTy::Us) => Ok(PrimVal::Ptr(ptr)),
|
2017-08-02 16:59:01 +02:00
|
|
|
TyInt(_) | TyUint(_) => err!(ReadPointerAsBytes),
|
|
|
|
_ => err!(Unimplemented(format!("ptr to {:?} cast", ty))),
|
2016-10-20 04:42:19 -06:00
|
|
|
}
|
|
|
|
}
|
2016-09-07 18:34:59 +02:00
|
|
|
}
|