116 lines
4.5 KiB
Rust
Raw Normal View History

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
use error::{EvalResult, EvalError};
2016-12-10 16:23:07 -08:00
use eval_context::EvalContext;
use value::PrimVal;
2016-09-07 18:34:59 +02:00
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
2016-11-26 22:58:01 -08:00
pub(super) fn cast_primval(
&self,
val: PrimVal,
src_ty: Ty<'tcx>,
dest_ty: Ty<'tcx>
) -> EvalResult<'tcx, PrimVal> {
let kind = self.ty_to_primval_kind(src_ty)?;
2016-12-10 16:23:07 -08:00
use value::PrimValKind::*;
2016-11-26 22:58:01 -08:00
match kind {
F32 => self.cast_float(val.to_f32()? as f64, dest_ty),
F64 => self.cast_float(val.to_f64()?, dest_ty),
2016-09-07 18:34:59 +02:00
I8 | I16 | I32 | I64 | I128 => {
if val.is_ptr() {
self.cast_ptr(val, dest_ty)
} else {
self.cast_signed_int(val.to_i128()?, dest_ty)
}
},
Bool | Char | U8 | U16 | U32 | U64 | U128 => {
if val.is_ptr() {
self.cast_ptr(val, dest_ty)
} else {
self.cast_int(val.to_u128()?, dest_ty, false)
}
},
2017-06-19 10:58:59 +02:00
FnPtr | Ptr => self.cast_ptr(val, dest_ty),
2016-09-07 18:34:59 +02:00
}
}
2017-01-12 08:28:42 +01:00
fn cast_signed_int(&self, val: i128, ty: ty::Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
self.cast_int(val as u128, ty, val < 0)
2016-09-07 18:34:59 +02:00
}
2017-01-12 08:28:42 +01:00
fn cast_int(&self, v: u128, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
2016-09-07 18:34:59 +02:00
match ty.sty {
// Casts to bool are not permitted by rustc, no need to handle them here.
2017-01-12 08:28:42 +01:00
TyInt(IntTy::I8) => Ok(PrimVal::Bytes(v as i128 as i8 as u128)),
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)),
2017-01-12 08:28:42 +01:00
TyUint(UintTy::U8) => Ok(PrimVal::Bytes(v as u8 as u128)),
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)),
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);
self.cast_int(v, ty, negative)
}
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);
self.cast_int(v, ty, negative)
}
2017-01-12 08:28:42 +01:00
TyFloat(FloatTy::F64) if negative => Ok(PrimVal::from_f64(v as i128 as f64)),
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)),
TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(v as f32)),
2017-01-12 08:28:42 +01:00
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
TyChar => Err(EvalError::InvalidChar(v)),
// No alignment check needed for raw pointers
2017-06-19 10:58:59 +02:00
TyRawPtr(_) => Ok(PrimVal::Bytes(v % (1 << self.memory.pointer_size()))),
2016-09-07 18:34:59 +02:00
_ => Err(EvalError::Unimplemented(format!("int to {:?} cast", ty))),
}
}
fn cast_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
2016-09-07 18:34:59 +02:00
match ty.sty {
// Casting negative floats to unsigned integers yields zero.
TyUint(_) if val < 0.0 => self.cast_int(0, ty, false),
2017-01-12 08:28:42 +01:00
TyInt(_) if val < 0.0 => self.cast_int(val as i128 as u128, ty, true),
2017-01-12 08:28:42 +01:00
TyInt(_) | ty::TyUint(_) => self.cast_int(val as u128, ty, false),
TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(val)),
TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(val as f32)),
2016-09-07 18:34:59 +02:00
_ => Err(EvalError::Unimplemented(format!("float to {:?} cast", ty))),
}
}
2017-06-19 10:58:59 +02:00
fn cast_ptr(&self, ptr: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
match ty.sty {
// Casting to a reference or fn pointer is not permitted by rustc, no need to support it here.
TyRawPtr(_) | TyInt(IntTy::Is) | TyUint(UintTy::Us) =>
2017-06-19 10:58:59 +02:00
Ok(ptr),
TyInt(_) | TyUint(_) => Err(EvalError::ReadPointerAsBytes),
_ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
}
}
2016-09-07 18:34:59 +02:00
}