1 use std::convert::TryFrom;
2 
3 use rustc_apfloat::ieee::{Double, Single};
4 use rustc_apfloat::{Float, FloatConvert};
5 use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
6 use rustc_middle::mir::CastKind;
7 use rustc_middle::ty::adjustment::PointerCast;
8 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
9 use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
10 use rustc_target::abi::{Integer, Variants};
11 
12 use super::{
13     util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy,
14 };
15 
16 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
cast( &mut self, src: &OpTy<'tcx, M::PointerTag>, cast_kind: CastKind, cast_ty: Ty<'tcx>, dest: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx>17     pub fn cast(
18         &mut self,
19         src: &OpTy<'tcx, M::PointerTag>,
20         cast_kind: CastKind,
21         cast_ty: Ty<'tcx>,
22         dest: &PlaceTy<'tcx, M::PointerTag>,
23     ) -> InterpResult<'tcx> {
24         use rustc_middle::mir::CastKind::*;
25         // FIXME: In which cases should we trigger UB when the source is uninit?
26         match cast_kind {
27             Pointer(PointerCast::Unsize) => {
28                 let cast_ty = self.layout_of(cast_ty)?;
29                 self.unsize_into(src, cast_ty, dest)?;
30             }
31 
32             Misc => {
33                 let src = self.read_immediate(src)?;
34                 let res = self.misc_cast(&src, cast_ty)?;
35                 self.write_immediate(res, dest)?;
36             }
37 
38             Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer) => {
39                 // These are NOPs, but can be wide pointers.
40                 let v = self.read_immediate(src)?;
41                 self.write_immediate(*v, dest)?;
42             }
43 
44             Pointer(PointerCast::ReifyFnPointer) => {
45                 // The src operand does not matter, just its type
46                 match *src.layout.ty.kind() {
47                     ty::FnDef(def_id, substs) => {
48                         // All reifications must be monomorphic, bail out otherwise.
49                         ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
50 
51                         let instance = ty::Instance::resolve_for_fn_ptr(
52                             *self.tcx,
53                             self.param_env,
54                             def_id,
55                             substs,
56                         )
57                         .ok_or_else(|| err_inval!(TooGeneric))?;
58 
59                         let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
60                         self.write_pointer(fn_ptr, dest)?;
61                     }
62                     _ => span_bug!(self.cur_span(), "reify fn pointer on {:?}", src.layout.ty),
63                 }
64             }
65 
66             Pointer(PointerCast::UnsafeFnPointer) => {
67                 let src = self.read_immediate(src)?;
68                 match cast_ty.kind() {
69                     ty::FnPtr(_) => {
70                         // No change to value
71                         self.write_immediate(*src, dest)?;
72                     }
73                     _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {:?}", cast_ty),
74                 }
75             }
76 
77             Pointer(PointerCast::ClosureFnPointer(_)) => {
78                 // The src operand does not matter, just its type
79                 match *src.layout.ty.kind() {
80                     ty::Closure(def_id, substs) => {
81                         // All reifications must be monomorphic, bail out otherwise.
82                         ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
83 
84                         let instance = ty::Instance::resolve_closure(
85                             *self.tcx,
86                             def_id,
87                             substs,
88                             ty::ClosureKind::FnOnce,
89                         );
90                         let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
91                         self.write_pointer(fn_ptr, dest)?;
92                     }
93                     _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty),
94                 }
95             }
96         }
97         Ok(())
98     }
99 
misc_cast( &self, src: &ImmTy<'tcx, M::PointerTag>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate<M::PointerTag>>100     fn misc_cast(
101         &self,
102         src: &ImmTy<'tcx, M::PointerTag>,
103         cast_ty: Ty<'tcx>,
104     ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
105         use rustc_middle::ty::TyKind::*;
106         trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty);
107 
108         match src.layout.ty.kind() {
109             // Floating point
110             Float(FloatTy::F32) => {
111                 return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, cast_ty).into());
112             }
113             Float(FloatTy::F64) => {
114                 return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, cast_ty).into());
115             }
116             // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
117             // are represented as integers.
118             _ => assert!(
119                 src.layout.ty.is_bool()
120                     || src.layout.ty.is_char()
121                     || src.layout.ty.is_enum()
122                     || src.layout.ty.is_integral()
123                     || src.layout.ty.is_any_ptr(),
124                 "Unexpected cast from type {:?}",
125                 src.layout.ty
126             ),
127         }
128 
129         // # First handle non-scalar source values.
130 
131         // Handle cast from a ZST enum (0 or 1 variants).
132         match src.layout.variants {
133             Variants::Single { index } => {
134                 if src.layout.abi.is_uninhabited() {
135                     // This is dead code, because an uninhabited enum is UB to
136                     // instantiate.
137                     throw_ub!(Unreachable);
138                 }
139                 if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
140                     assert!(src.layout.is_zst());
141                     let discr_layout = self.layout_of(discr.ty)?;
142                     return Ok(self.cast_from_scalar(discr.val, discr_layout, cast_ty).into());
143                 }
144             }
145             Variants::Multiple { .. } => {}
146         }
147 
148         // Handle casting any ptr to raw ptr (might be a fat ptr).
149         if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() {
150             let dest_layout = self.layout_of(cast_ty)?;
151             if dest_layout.size == src.layout.size {
152                 // Thin or fat pointer that just hast the ptr kind of target type changed.
153                 return Ok(**src);
154             } else {
155                 // Casting the metadata away from a fat ptr.
156                 assert_eq!(src.layout.size, 2 * self.memory.pointer_size());
157                 assert_eq!(dest_layout.size, self.memory.pointer_size());
158                 assert!(src.layout.ty.is_unsafe_ptr());
159                 return match **src {
160                     Immediate::ScalarPair(data, _) => Ok(data.into()),
161                     Immediate::Scalar(..) => span_bug!(
162                         self.cur_span(),
163                         "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
164                         *src,
165                         src.layout.ty,
166                         cast_ty
167                     ),
168                 };
169             }
170         }
171 
172         // # The remaining source values are scalar.
173 
174         // For all remaining casts, we either
175         // (a) cast a raw ptr to usize, or
176         // (b) cast from an integer-like (including bool, char, enums).
177         // In both cases we want the bits.
178         let bits = src.to_scalar()?.to_bits(src.layout.size)?;
179         Ok(self.cast_from_scalar(bits, src.layout, cast_ty).into())
180     }
181 
cast_from_scalar( &self, v: u128, src_layout: TyAndLayout<'tcx>, cast_ty: Ty<'tcx>, ) -> Scalar<M::PointerTag>182     pub(super) fn cast_from_scalar(
183         &self,
184         v: u128, // raw bits (there is no ScalarTy so we separate data+layout)
185         src_layout: TyAndLayout<'tcx>,
186         cast_ty: Ty<'tcx>,
187     ) -> Scalar<M::PointerTag> {
188         // Let's make sure v is sign-extended *if* it has a signed type.
189         let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`.
190         let v = if signed { self.sign_extend(v, src_layout) } else { v };
191         trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty);
192         use rustc_middle::ty::TyKind::*;
193         match *cast_ty.kind() {
194             Int(_) | Uint(_) | RawPtr(_) => {
195                 let size = match *cast_ty.kind() {
196                     Int(t) => Integer::from_int_ty(self, t).size(),
197                     Uint(t) => Integer::from_uint_ty(self, t).size(),
198                     RawPtr(_) => self.pointer_size(),
199                     _ => bug!(),
200                 };
201                 let v = size.truncate(v);
202                 Scalar::from_uint(v, size)
203             }
204 
205             Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value),
206             Float(FloatTy::F64) if signed => Scalar::from_f64(Double::from_i128(v as i128).value),
207             Float(FloatTy::F32) => Scalar::from_f32(Single::from_u128(v).value),
208             Float(FloatTy::F64) => Scalar::from_f64(Double::from_u128(v).value),
209 
210             Char => {
211                 // `u8` to `char` cast
212                 Scalar::from_u32(u8::try_from(v).unwrap().into())
213             }
214 
215             // Casts to bool are not permitted by rustc, no need to handle them here.
216             _ => span_bug!(self.cur_span(), "invalid int to {:?} cast", cast_ty),
217         }
218     }
219 
cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::PointerTag> where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>,220     fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::PointerTag>
221     where
222         F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>,
223     {
224         use rustc_middle::ty::TyKind::*;
225         match *dest_ty.kind() {
226             // float -> uint
227             Uint(t) => {
228                 let size = Integer::from_uint_ty(self, t).size();
229                 // `to_u128` is a saturating cast, which is what we need
230                 // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r).
231                 let v = f.to_u128(size.bits_usize()).value;
232                 // This should already fit the bit width
233                 Scalar::from_uint(v, size)
234             }
235             // float -> int
236             Int(t) => {
237                 let size = Integer::from_int_ty(self, t).size();
238                 // `to_i128` is a saturating cast, which is what we need
239                 // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r).
240                 let v = f.to_i128(size.bits_usize()).value;
241                 Scalar::from_int(v, size)
242             }
243             // float -> f32
244             Float(FloatTy::F32) => Scalar::from_f32(f.convert(&mut false).value),
245             // float -> f64
246             Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value),
247             // That's it.
248             _ => span_bug!(self.cur_span(), "invalid float to {:?} cast", dest_ty),
249         }
250     }
251 
unsize_into_ptr( &mut self, src: &OpTy<'tcx, M::PointerTag>, dest: &PlaceTy<'tcx, M::PointerTag>, source_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx>252     fn unsize_into_ptr(
253         &mut self,
254         src: &OpTy<'tcx, M::PointerTag>,
255         dest: &PlaceTy<'tcx, M::PointerTag>,
256         // The pointee types
257         source_ty: Ty<'tcx>,
258         cast_ty: Ty<'tcx>,
259     ) -> InterpResult<'tcx> {
260         // A<Struct> -> A<Trait> conversion
261         let (src_pointee_ty, dest_pointee_ty) =
262             self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env);
263 
264         match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
265             (&ty::Array(_, length), &ty::Slice(_)) => {
266                 let ptr = self.read_immediate(src)?.to_scalar()?;
267                 // u64 cast is from usize to u64, which is always good
268                 let val =
269                     Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self);
270                 self.write_immediate(val, dest)
271             }
272             (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
273                 let val = self.read_immediate(src)?;
274                 if data_a.principal_def_id() == data_b.principal_def_id() {
275                     return self.write_immediate(*val, dest);
276                 }
277                 // trait upcasting coercion
278                 let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
279                     src_pointee_ty,
280                     dest_pointee_ty,
281                 ));
282 
283                 if let Some(entry_idx) = vptr_entry_idx {
284                     let entry_idx = u64::try_from(entry_idx).unwrap();
285                     let (old_data, old_vptr) = val.to_scalar_pair()?;
286                     let old_vptr = self.scalar_to_ptr(old_vptr);
287                     let new_vptr = self
288                         .read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?;
289                     self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
290                 } else {
291                     self.write_immediate(*val, dest)
292                 }
293             }
294             (_, &ty::Dynamic(ref data, _)) => {
295                 // Initial cast from sized to dyn trait
296                 let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
297                 let ptr = self.read_immediate(src)?.to_scalar()?;
298                 let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx);
299                 self.write_immediate(val, dest)
300             }
301 
302             _ => {
303                 span_bug!(self.cur_span(), "invalid unsizing {:?} -> {:?}", src.layout.ty, cast_ty)
304             }
305         }
306     }
307 
unsize_into( &mut self, src: &OpTy<'tcx, M::PointerTag>, cast_ty: TyAndLayout<'tcx>, dest: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx>308     fn unsize_into(
309         &mut self,
310         src: &OpTy<'tcx, M::PointerTag>,
311         cast_ty: TyAndLayout<'tcx>,
312         dest: &PlaceTy<'tcx, M::PointerTag>,
313     ) -> InterpResult<'tcx> {
314         trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty);
315         match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
316             (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. }))
317             | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => {
318                 self.unsize_into_ptr(src, dest, s, c)
319             }
320             (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
321                 assert_eq!(def_a, def_b);
322                 if def_a.is_box() || def_b.is_box() {
323                     if !def_a.is_box() || !def_b.is_box() {
324                         span_bug!(
325                             self.cur_span(),
326                             "invalid unsizing between {:?} -> {:?}",
327                             src.layout.ty,
328                             cast_ty.ty
329                         );
330                     }
331                     return self.unsize_into_ptr(
332                         src,
333                         dest,
334                         src.layout.ty.boxed_ty(),
335                         cast_ty.ty.boxed_ty(),
336                     );
337                 }
338 
339                 // unsizing of generic struct with pointer fields
340                 // Example: `Arc<T>` -> `Arc<Trait>`
341                 // here we need to increase the size of every &T thin ptr field to a fat ptr
342                 for i in 0..src.layout.fields.count() {
343                     let cast_ty_field = cast_ty.field(self, i);
344                     if cast_ty_field.is_zst() {
345                         continue;
346                     }
347                     let src_field = self.operand_field(src, i)?;
348                     let dst_field = self.place_field(dest, i)?;
349                     if src_field.layout.ty == cast_ty_field.ty {
350                         self.copy_op(&src_field, &dst_field)?;
351                     } else {
352                         self.unsize_into(&src_field, cast_ty_field, &dst_field)?;
353                     }
354                 }
355                 Ok(())
356             }
357             _ => span_bug!(
358                 self.cur_span(),
359                 "unsize_into: invalid conversion: {:?} -> {:?}",
360                 src.layout,
361                 dest.layout
362             ),
363         }
364     }
365 }
366