1 use rustc::ty::{self, Ty};
2 use rustc::ty::layout::{self, LayoutOf, TyLayout};
3 use syntax::ast::{FloatTy, IntTy, UintTy};
5 use rustc_apfloat::ieee::{Single, Double};
6 use super::{EvalContext, Machine};
7 use rustc::mir::interpret::{Scalar, EvalResult, Pointer, PointerArithmetic, Value, EvalErrorKind};
8 use rustc::mir::CastKind;
9 use rustc_apfloat::Float;
10 use interpret::eval_context::ValTy;
13 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
20 ) -> EvalResult<'tcx> {
21 let src_layout = self.layout_of(src.ty)?;
22 let dst_layout = self.layout_of(dest_ty)?;
23 use rustc::mir::CastKind::*;
26 self.unsize_into(src.value, src_layout, dest, dst_layout)?;
30 if self.type_is_fat_ptr(src.ty) {
31 match (src.value, self.type_is_fat_ptr(dest_ty)) {
32 (Value::ByRef { .. }, _) |
33 // pointers to extern types
34 (Value::Scalar(_),_) |
35 // slices and trait objects to other slices/trait objects
36 (Value::ScalarPair(..), true) => {
41 self.write_value(valty, dest)?;
43 // slices and trait objects to thin pointers (dropping the metadata)
44 (Value::ScalarPair(data, _), false) => {
46 value: Value::Scalar(data),
49 self.write_value(valty, dest)?;
53 let src_layout = self.layout_of(src.ty)?;
54 match src_layout.variants {
55 layout::Variants::Single { index } => {
56 if let Some(def) = src.ty.ty_adt_def() {
58 .discriminant_for_variant(*self.tcx, index)
60 return self.write_scalar(
64 size: dst_layout.size.bytes() as u8,
69 layout::Variants::Tagged { .. } |
70 layout::Variants::NicheFilling { .. } => {},
73 let src_val = self.value_to_scalar(src)?;
74 let dest_val = self.cast_scalar(src_val, src_layout, dst_layout)?;
76 value: Value::Scalar(dest_val.into()),
79 self.write_value(valty, dest)?;
85 ty::TyFnDef(def_id, substs) => {
86 if self.tcx.has_attr(def_id, "rustc_args_required_const") {
87 bug!("reifying a fn ptr that requires \
90 let instance: EvalResult<'tcx, _> = ty::Instance::resolve(
95 ).ok_or_else(|| EvalErrorKind::TooGeneric.into());
96 let fn_ptr = self.memory.create_fn_alloc(instance?);
98 value: Value::Scalar(Scalar::Ptr(fn_ptr.into()).into()),
101 self.write_value(valty, dest)?;
103 ref other => bug!("reify fn pointer on {:?}", other),
112 self.write_value(src, dest)?;
114 ref other => bug!("fn to unsafe fn cast on {:?}", other),
118 ClosureFnPointer => {
120 ty::TyClosure(def_id, substs) => {
121 let substs = self.tcx.subst_and_normalize_erasing_regions(
123 ty::ParamEnv::reveal_all(),
126 let instance = ty::Instance::resolve_closure(
130 ty::ClosureKind::FnOnce,
132 let fn_ptr = self.memory.create_fn_alloc(instance);
134 value: Value::Scalar(Scalar::Ptr(fn_ptr.into()).into()),
137 self.write_value(valty, dest)?;
139 ref other => bug!("closure fn pointer on {:?}", other),
146 pub(super) fn cast_scalar(
149 src_layout: TyLayout<'tcx>,
150 dest_layout: TyLayout<'tcx>,
151 ) -> EvalResult<'tcx, Scalar> {
152 use rustc::ty::TypeVariants::*;
153 trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
156 Scalar::Ptr(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
157 Scalar::Bits { bits, size } => {
158 assert_eq!(size as u64, src_layout.size.bytes());
159 match src_layout.ty.sty {
160 TyFloat(fty) => self.cast_from_float(bits, fty, dest_layout.ty),
161 _ => self.cast_from_int(bits, src_layout, dest_layout),
170 src_layout: TyLayout<'tcx>,
171 dest_layout: TyLayout<'tcx>,
172 ) -> EvalResult<'tcx, Scalar> {
173 let signed = src_layout.abi.is_signed();
175 self.sign_extend(v, src_layout)
179 trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty);
180 use rustc::ty::TypeVariants::*;
181 match dest_layout.ty.sty {
182 TyInt(_) | TyUint(_) => {
183 let v = self.truncate(v, dest_layout);
186 size: dest_layout.size.bytes() as u8,
190 TyFloat(FloatTy::F32) if signed => Ok(Scalar::Bits {
191 bits: Single::from_i128(v as i128).value.to_bits(),
194 TyFloat(FloatTy::F64) if signed => Ok(Scalar::Bits {
195 bits: Double::from_i128(v as i128).value.to_bits(),
198 TyFloat(FloatTy::F32) => Ok(Scalar::Bits {
199 bits: Single::from_u128(v).value.to_bits(),
202 TyFloat(FloatTy::F64) => Ok(Scalar::Bits {
203 bits: Double::from_u128(v).value.to_bits(),
208 assert_eq!(v as u8 as u128, v);
209 Ok(Scalar::Bits { bits: v, size: 4 })
212 // No alignment check needed for raw pointers. But we have to truncate to target ptr size.
215 bits: self.memory.truncate_to_ptr(v).0 as u128,
216 size: self.memory.pointer_size().bytes() as u8,
220 // Casts to bool are not permitted by rustc, no need to handle them here.
221 _ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
225 fn cast_from_float(&self, bits: u128, fty: FloatTy, dest_ty: Ty<'tcx>) -> EvalResult<'tcx, Scalar> {
226 use rustc::ty::TypeVariants::*;
227 use rustc_apfloat::FloatConvert;
231 let width = t.bit_width().unwrap_or(self.memory.pointer_size().bits() as usize);
233 FloatTy::F32 => Ok(Scalar::Bits {
234 bits: Single::from_bits(bits).to_u128(width).value,
235 size: (width / 8) as u8,
237 FloatTy::F64 => Ok(Scalar::Bits {
238 bits: Double::from_bits(bits).to_u128(width).value,
239 size: (width / 8) as u8,
245 let width = t.bit_width().unwrap_or(self.memory.pointer_size().bits() as usize);
247 FloatTy::F32 => Ok(Scalar::Bits {
248 bits: Single::from_bits(bits).to_i128(width).value as u128,
249 size: (width / 8) as u8,
251 FloatTy::F64 => Ok(Scalar::Bits {
252 bits: Double::from_bits(bits).to_i128(width).value as u128,
253 size: (width / 8) as u8,
258 TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
260 bits: Single::to_bits(Double::from_bits(bits).convert(&mut false).value),
265 TyFloat(FloatTy::F64) if fty == FloatTy::F32 => {
267 bits: Double::to_bits(Single::from_bits(bits).convert(&mut false).value),
272 TyFloat(FloatTy:: F64) => Ok(Scalar::Bits {
276 TyFloat(FloatTy:: F32) => Ok(Scalar::Bits {
280 _ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
284 fn cast_from_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Scalar> {
285 use rustc::ty::TypeVariants::*;
287 // Casting to a reference or fn pointer is not permitted by rustc, no need to support it here.
289 TyInt(IntTy::Isize) |
290 TyUint(UintTy::Usize) => Ok(ptr.into()),
291 TyInt(_) | TyUint(_) => err!(ReadPointerAsBytes),
292 _ => err!(Unimplemented(format!("ptr to {:?} cast", ty))),