]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/interpret/cast.rs
New upstream version 1.26.0+dfsg1
[rustc.git] / src / librustc_mir / interpret / cast.rs
1 use rustc::ty::Ty;
2 use rustc::ty::layout::LayoutOf;
3 use syntax::ast::{FloatTy, IntTy, UintTy};
4
5 use rustc_const_math::ConstFloat;
6 use super::{EvalContext, Machine};
7 use rustc::mir::interpret::{PrimVal, EvalResult, MemoryPointer, PointerArithmetic};
8 use rustc_apfloat::ieee::{Single, Double};
9 use rustc_apfloat::Float;
10
11 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
12 pub(super) fn cast_primval(
13 &self,
14 val: PrimVal,
15 src_ty: Ty<'tcx>,
16 dest_ty: Ty<'tcx>,
17 ) -> EvalResult<'tcx, PrimVal> {
18 use rustc::ty::TypeVariants::*;
19 trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
20
21 match val {
22 PrimVal::Undef => Ok(PrimVal::Undef),
23 PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
24 PrimVal::Bytes(b) => {
25 match src_ty.sty {
26 TyFloat(fty) => self.cast_from_float(b, fty, dest_ty),
27 _ => self.cast_from_int(b, src_ty, dest_ty),
28 }
29 }
30 }
31 }
32
33 fn cast_from_int(
34 &self,
35 v: u128,
36 src_ty: Ty<'tcx>,
37 dest_ty: Ty<'tcx>,
38 ) -> EvalResult<'tcx, PrimVal> {
39 let signed = self.layout_of(src_ty)?.abi.is_signed();
40 let v = if signed {
41 self.sign_extend(v, src_ty)?
42 } else {
43 v
44 };
45 trace!("cast_from_int: {}, {}, {}", v, src_ty, dest_ty);
46 use rustc::ty::TypeVariants::*;
47 match dest_ty.sty {
48 TyInt(_) | TyUint(_) => {
49 let v = self.truncate(v, dest_ty)?;
50 Ok(PrimVal::Bytes(v))
51 }
52
53 TyFloat(fty) if signed => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)),
54 TyFloat(fty) => Ok(PrimVal::Bytes(ConstFloat::from_u128(v, fty).bits)),
55
56 TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
57 TyChar => err!(InvalidChar(v)),
58
59 // No alignment check needed for raw pointers. But we have to truncate to target ptr size.
60 TyRawPtr(_) => {
61 Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128))
62 },
63
64 // Casts to bool are not permitted by rustc, no need to handle them here.
65 _ => err!(Unimplemented(format!("int to {:?} cast", dest_ty))),
66 }
67 }
68
69 fn cast_from_float(&self, bits: u128, fty: FloatTy, dest_ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
70 use rustc::ty::TypeVariants::*;
71 use rustc_apfloat::FloatConvert;
72 match dest_ty.sty {
73 // float -> uint
74 TyUint(t) => {
75 let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
76 match fty {
77 FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(bits).to_u128(width).value)),
78 FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(bits).to_u128(width).value)),
79 }
80 },
81 // float -> int
82 TyInt(t) => {
83 let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
84 match fty {
85 FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(bits).to_i128(width).value)),
86 FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(bits).to_i128(width).value)),
87 }
88 },
89 // f64 -> f32
90 TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
91 Ok(PrimVal::Bytes(Single::to_bits(Double::from_bits(bits).convert(&mut false).value)))
92 },
93 // f32 -> f64
94 TyFloat(FloatTy::F64) if fty == FloatTy::F32 => {
95 Ok(PrimVal::Bytes(Double::to_bits(Single::from_bits(bits).convert(&mut false).value)))
96 },
97 // identity cast
98 TyFloat(_) => Ok(PrimVal::Bytes(bits)),
99 _ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
100 }
101 }
102
103 fn cast_from_ptr(&self, ptr: MemoryPointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
104 use rustc::ty::TypeVariants::*;
105 match ty.sty {
106 // Casting to a reference or fn pointer is not permitted by rustc, no need to support it here.
107 TyRawPtr(_) |
108 TyInt(IntTy::Isize) |
109 TyUint(UintTy::Usize) => Ok(PrimVal::Ptr(ptr)),
110 TyInt(_) | TyUint(_) => err!(ReadPointerAsBytes),
111 _ => err!(Unimplemented(format!("ptr to {:?} cast", ty))),
112 }
113 }
114 }