]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/interpret/cast.rs
New upstream version 1.25.0+dfsg1
[rustc.git] / src / librustc_mir / interpret / cast.rs
1 use rustc::ty::Ty;
2 use syntax::ast::{FloatTy, IntTy, UintTy};
3
4 use rustc_const_math::ConstFloat;
5 use super::{EvalContext, Machine};
6 use rustc::mir::interpret::{PrimVal, EvalResult, MemoryPointer, PointerArithmetic};
7 use rustc_apfloat::ieee::{Single, Double};
8 use rustc_apfloat::Float;
9
10 impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
11 pub(super) fn cast_primval(
12 &self,
13 val: PrimVal,
14 src_ty: Ty<'tcx>,
15 dest_ty: Ty<'tcx>,
16 ) -> EvalResult<'tcx, PrimVal> {
17 trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
18 let src_kind = self.ty_to_primval_kind(src_ty)?;
19
20 match val {
21 PrimVal::Undef => Ok(PrimVal::Undef),
22 PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
23 val @ PrimVal::Bytes(_) => {
24 use rustc::mir::interpret::PrimValKind::*;
25 match src_kind {
26 F32 => self.cast_from_float(val.to_f32()?, dest_ty),
27 F64 => self.cast_from_float(val.to_f64()?, dest_ty),
28
29 I8 | I16 | I32 | I64 | I128 => {
30 self.cast_from_signed_int(val.to_i128()?, dest_ty)
31 }
32
33 Bool | Char | U8 | U16 | U32 | U64 | U128 | FnPtr | Ptr => {
34 self.cast_from_int(val.to_u128()?, dest_ty, false)
35 }
36 }
37 }
38 }
39 }
40
41 fn cast_from_signed_int(&self, val: i128, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
42 self.cast_from_int(val as u128, ty, val < 0)
43 }
44
45 fn int_to_int(&self, v: i128, ty: IntTy) -> u128 {
46 match ty {
47 IntTy::I8 => v as i8 as u128,
48 IntTy::I16 => v as i16 as u128,
49 IntTy::I32 => v as i32 as u128,
50 IntTy::I64 => v as i64 as u128,
51 IntTy::I128 => v as u128,
52 IntTy::Isize => {
53 let ty = self.tcx.sess.target.isize_ty;
54 self.int_to_int(v, ty)
55 }
56 }
57 }
58 fn int_to_uint(&self, v: u128, ty: UintTy) -> u128 {
59 match ty {
60 UintTy::U8 => v as u8 as u128,
61 UintTy::U16 => v as u16 as u128,
62 UintTy::U32 => v as u32 as u128,
63 UintTy::U64 => v as u64 as u128,
64 UintTy::U128 => v,
65 UintTy::Usize => {
66 let ty = self.tcx.sess.target.usize_ty;
67 self.int_to_uint(v, ty)
68 }
69 }
70 }
71
72 fn cast_from_int(
73 &self,
74 v: u128,
75 ty: Ty<'tcx>,
76 negative: bool,
77 ) -> EvalResult<'tcx, PrimVal> {
78 trace!("cast_from_int: {}, {}, {}", v, ty, negative);
79 use rustc::ty::TypeVariants::*;
80 match ty.sty {
81 // Casts to bool are not permitted by rustc, no need to handle them here.
82 TyInt(ty) => Ok(PrimVal::Bytes(self.int_to_int(v as i128, ty))),
83 TyUint(ty) => Ok(PrimVal::Bytes(self.int_to_uint(v, ty))),
84
85 TyFloat(fty) if negative => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)),
86 TyFloat(fty) => Ok(PrimVal::Bytes(ConstFloat::from_u128(v, fty).bits)),
87
88 TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
89 TyChar => err!(InvalidChar(v)),
90
91 // No alignment check needed for raw pointers. But we have to truncate to target ptr size.
92 TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)),
93
94 _ => err!(Unimplemented(format!("int to {:?} cast", ty))),
95 }
96 }
97
98 fn cast_from_float(&self, val: ConstFloat, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
99 use rustc::ty::TypeVariants::*;
100 match ty.sty {
101 TyUint(t) => {
102 let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
103 match val.ty {
104 FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(val.bits).to_u128(width).value)),
105 FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(val.bits).to_u128(width).value)),
106 }
107 },
108
109 TyInt(t) => {
110 let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
111 match val.ty {
112 FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(val.bits).to_i128(width).value)),
113 FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(val.bits).to_i128(width).value)),
114 }
115 },
116
117 TyFloat(fty) => Ok(PrimVal::from_float(val.convert(fty))),
118 _ => err!(Unimplemented(format!("float to {:?} cast", ty))),
119 }
120 }
121
122 fn cast_from_ptr(&self, ptr: MemoryPointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
123 use rustc::ty::TypeVariants::*;
124 match ty.sty {
125 // Casting to a reference or fn pointer is not permitted by rustc, no need to support it here.
126 TyRawPtr(_) |
127 TyInt(IntTy::Isize) |
128 TyUint(UintTy::Usize) => Ok(PrimVal::Ptr(ptr)),
129 TyInt(_) | TyUint(_) => err!(ReadPointerAsBytes),
130 _ => err!(Unimplemented(format!("ptr to {:?} cast", ty))),
131 }
132 }
133 }