diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_const_eval/src/interpret/cast.rs | 143 |
1 files changed, 92 insertions, 51 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index c97c31eb9..269ae15d4 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -43,9 +43,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_immediate(res, dest)?; } - Misc => { + IntToInt | IntToFloat => { let src = self.read_immediate(src)?; - let res = self.misc_cast(&src, cast_ty)?; + let res = self.int_to_int_or_float(&src, cast_ty)?; + self.write_immediate(res, dest)?; + } + + FloatToFloat | FloatToInt => { + let src = self.read_immediate(src)?; + let res = self.float_to_float_or_int(&src, cast_ty)?; + self.write_immediate(res, dest)?; + } + + FnPtrToPtr | PtrToPtr => { + let src = self.read_immediate(&src)?; + let res = self.ptr_to_ptr(&src, cast_ty)?; self.write_immediate(res, dest)?; } @@ -108,67 +120,88 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty), } } + + DynStar => { + if let ty::Dynamic(data, _, ty::DynStar) = cast_ty.kind() { + // Initial cast from sized to dyn trait + let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?; + let vtable = Scalar::from_maybe_pointer(vtable, self); + let data = self.read_immediate(src)?.to_scalar(); + let _assert_pointer_sized = data.to_pointer(self)?; + let val = Immediate::ScalarPair(data, vtable); + self.write_immediate(val, dest)?; + } else { + bug!() + } + } } Ok(()) } - pub fn misc_cast( - &mut self, + /// Handles 'IntToInt' and 'IntToFloat' casts. + pub fn int_to_int_or_float( + &self, + src: &ImmTy<'tcx, M::Provenance>, + cast_ty: Ty<'tcx>, + ) -> InterpResult<'tcx, Immediate<M::Provenance>> { + assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool()); + assert!(cast_ty.is_floating_point() || cast_ty.is_integral() || cast_ty.is_char()); + + Ok(self.cast_from_int_like(src.to_scalar(), src.layout, cast_ty)?.into()) + } + + /// Handles 'FloatToFloat' and 'FloatToInt' casts. + pub fn float_to_float_or_int( + &self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate<M::Provenance>> { use rustc_type_ir::sty::TyKind::*; - trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty); match src.layout.ty.kind() { // Floating point Float(FloatTy::F32) => { - return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, cast_ty).into()); + return Ok(self.cast_from_float(src.to_scalar().to_f32()?, cast_ty).into()); } Float(FloatTy::F64) => { - return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, cast_ty).into()); + return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into()); + } + _ => { + bug!("Can't cast 'Float' type into {:?}", cast_ty); } - // The rest is integer/pointer-"like", including fn ptr casts - _ => assert!( - src.layout.ty.is_bool() - || src.layout.ty.is_char() - || src.layout.ty.is_integral() - || src.layout.ty.is_any_ptr(), - "Unexpected cast from type {:?}", - src.layout.ty - ), } + } - // # First handle non-scalar source values. - + /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts. + pub fn ptr_to_ptr( + &self, + src: &ImmTy<'tcx, M::Provenance>, + cast_ty: Ty<'tcx>, + ) -> InterpResult<'tcx, Immediate<M::Provenance>> { + assert!(src.layout.ty.is_any_ptr()); + assert!(cast_ty.is_unsafe_ptr()); // Handle casting any ptr to raw ptr (might be a fat ptr). - if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() { - let dest_layout = self.layout_of(cast_ty)?; - if dest_layout.size == src.layout.size { - // Thin or fat pointer that just hast the ptr kind of target type changed. - return Ok(**src); - } else { - // Casting the metadata away from a fat ptr. - assert_eq!(src.layout.size, 2 * self.pointer_size()); - assert_eq!(dest_layout.size, self.pointer_size()); - assert!(src.layout.ty.is_unsafe_ptr()); - return match **src { - Immediate::ScalarPair(data, _) => Ok(data.check_init()?.into()), - Immediate::Scalar(..) => span_bug!( - self.cur_span(), - "{:?} input to a fat-to-thin cast ({:?} -> {:?})", - *src, - src.layout.ty, - cast_ty - ), - Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), - }; - } + let dest_layout = self.layout_of(cast_ty)?; + if dest_layout.size == src.layout.size { + // Thin or fat pointer that just hast the ptr kind of target type changed. + return Ok(**src); + } else { + // Casting the metadata away from a fat ptr. + assert_eq!(src.layout.size, 2 * self.pointer_size()); + assert_eq!(dest_layout.size, self.pointer_size()); + assert!(src.layout.ty.is_unsafe_ptr()); + return match **src { + Immediate::ScalarPair(data, _) => Ok(data.into()), + Immediate::Scalar(..) => span_bug!( + self.cur_span(), + "{:?} input to a fat-to-thin cast ({:?} -> {:?})", + *src, + src.layout.ty, + cast_ty + ), + Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), + }; } - - // # The remaining source values are scalar and "int-like". - let scalar = src.to_scalar()?; - Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) } pub fn pointer_expose_address_cast( @@ -179,7 +212,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_)); assert!(cast_ty.is_integral()); - let scalar = src.to_scalar()?; + let scalar = src.to_scalar(); let ptr = scalar.to_pointer(self)?; match ptr.into_pointer_or_addr() { Ok(ptr) => M::expose_ptr(self, ptr)?, @@ -189,7 +222,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } pub fn pointer_from_exposed_address_cast( - &mut self, + &self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate<M::Provenance>> { @@ -197,7 +230,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_matches!(cast_ty.kind(), ty::RawPtr(_)); // First cast to usize. - let scalar = src.to_scalar()?; + let scalar = src.to_scalar(); let addr = self.cast_from_int_like(scalar, src.layout, self.tcx.types.usize)?; let addr = addr.to_machine_usize(self)?; @@ -206,6 +239,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(Scalar::from_maybe_pointer(ptr, self).into()) } + /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input + /// type (basically everything with a scalar layout) to int/float/char types. pub fn cast_from_int_like( &self, scalar: Scalar<M::Provenance>, // input value (there is no ScalarTy so we separate data+layout) @@ -245,6 +280,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) } + /// Low-level cast helper function. Converts an apfloat `f` into int or float types. fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance> where F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>, @@ -291,14 +327,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) { (&ty::Array(_, length), &ty::Slice(_)) => { - let ptr = self.read_immediate(src)?.to_scalar()?; + let ptr = self.read_scalar(src)?; // u64 cast is from usize to u64, which is always good let val = Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self); self.write_immediate(val, dest) } (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { - let (old_data, old_vptr) = self.read_immediate(src)?.to_scalar_pair()?; + let val = self.read_immediate(src)?; + if data_a.principal() == data_b.principal() { + // A NOP cast that doesn't actually change anything, should be allowed even with mismatching vtables. + return self.write_immediate(*val, dest); + } + let (old_data, old_vptr) = val.to_scalar_pair(); let old_vptr = old_vptr.to_pointer(self)?; let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?; if old_trait != data_a.principal() { @@ -307,10 +348,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) } - (_, &ty::Dynamic(ref data, _)) => { + (_, &ty::Dynamic(ref data, _, ty::Dyn)) => { // Initial cast from sized to dyn trait let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?; - let ptr = self.read_immediate(src)?.to_scalar()?; + let ptr = self.read_scalar(src)?; let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx); self.write_immediate(val, dest) } |