diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index ddc4bd3f9f6c3..5cc46b21fca1f 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2035,6 +2035,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] + pub fn is_fn_ptr(&self) -> bool { + match self.sty { + FnPtr(_) => true, + _ => false, + } + } + pub fn is_impl_trait(&self) -> bool { match self.sty { Opaque(..) => true, diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 4395f0c947b15..7a0c98bc44c37 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -5,11 +5,11 @@ use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::symbol::sym; use rustc_apfloat::ieee::{Single, Double}; +use rustc_apfloat::{Float, FloatConvert}; use rustc::mir::interpret::{ Scalar, InterpResult, Pointer, PointerArithmetic, InterpError, }; use rustc::mir::CastKind; -use rustc_apfloat::Float; use super::{InterpretCx, Machine, PlaceTy, OpTy, Immediate}; @@ -126,7 +126,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> Ok(()) } - pub(super) fn cast_scalar( + fn cast_scalar( &self, val: Scalar, src_layout: TyLayout<'tcx>, @@ -135,12 +135,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> use rustc::ty::TyKind::*; trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty); - match val.to_bits_or_ptr(src_layout.size, self) { - Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty), - Ok(data) => { - match src_layout.ty.sty { - Float(fty) => self.cast_from_float(data, fty, dest_layout.ty), - _ => self.cast_from_int(data, src_layout, dest_layout), + match src_layout.ty.sty { + // Floating point + Float(FloatTy::F32) => self.cast_from_float(val.to_f32()?, dest_layout.ty), + Float(FloatTy::F64) => self.cast_from_float(val.to_f64()?, dest_layout.ty), + // Integer(-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_region_ptr() || + src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_ptr(), + "Unexpected cast from type {:?}", src_layout.ty + ); + match val.to_bits_or_ptr(src_layout.size, self) { + Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty), + Ok(data) => self.cast_from_int(data, src_layout, dest_layout), } } } @@ -148,10 +157,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> fn cast_from_int( &self, - v: u128, + v: u128, // raw bits src_layout: TyLayout<'tcx>, dest_layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, Scalar> { + // Let's make sure v is sign-extended *if* it has a signed type. let signed = src_layout.abi.is_signed(); let v = if signed { self.sign_extend(v, src_layout) @@ -190,46 +200,36 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> } } - fn cast_from_float( + fn cast_from_float( &self, - bits: u128, - fty: FloatTy, + f: F, dest_ty: Ty<'tcx> - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> + where F: Float + Into> + FloatConvert + FloatConvert + { use rustc::ty::TyKind::*; - use rustc_apfloat::FloatConvert; match dest_ty.sty { // float -> uint Uint(t) => { let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize); - let v = match fty { - FloatTy::F32 => Single::from_bits(bits).to_u128(width).value, - FloatTy::F64 => Double::from_bits(bits).to_u128(width).value, - }; + let v = f.to_u128(width).value; // This should already fit the bit width Ok(Scalar::from_uint(v, Size::from_bits(width as u64))) }, // float -> int Int(t) => { let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize); - let v = match fty { - FloatTy::F32 => Single::from_bits(bits).to_i128(width).value, - FloatTy::F64 => Double::from_bits(bits).to_i128(width).value, - }; + let v = f.to_i128(width).value; Ok(Scalar::from_int(v, Size::from_bits(width as u64))) }, - // f64 -> f32 - Float(FloatTy::F32) if fty == FloatTy::F64 => - Ok(Scalar::from_f32(Double::from_bits(bits).convert(&mut false).value)), - // f32 -> f64 - Float(FloatTy::F64) if fty == FloatTy::F32 => - Ok(Scalar::from_f64(Single::from_bits(bits).convert(&mut false).value)), - // identity cast - Float(FloatTy::F64) if fty == FloatTy::F64 => - Ok(Scalar::from_uint(bits, Size::from_bits(64))), - Float(FloatTy::F32) if fty == FloatTy::F32 => - Ok(Scalar::from_uint(bits, Size::from_bits(32))), - _ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))), + // float -> f32 + Float(FloatTy::F32) => + Ok(Scalar::from_f32(f.convert(&mut false).value)), + // float -> f64 + Float(FloatTy::F64) => + Ok(Scalar::from_f64(f.convert(&mut false).value)), + // That's it. + _ => bug!("invalid float to {:?} cast", dest_ty), } } diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index eb45bb0e2771b..db7da9359de7b 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -292,10 +292,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> } _ => { // Must be integer(-like) types. Don't forget about == on fn pointers. - assert!(left.layout.ty.is_integral() || left.layout.ty.is_unsafe_ptr() || - left.layout.ty.is_fn()); - assert!(right.layout.ty.is_integral() || right.layout.ty.is_unsafe_ptr() || - right.layout.ty.is_fn()); + assert!( + left.layout.ty.is_integral() || + left.layout.ty.is_unsafe_ptr() || left.layout.ty.is_fn_ptr(), + "Unexpected LHS type {:?} for BinOp {:?}", left.layout.ty, bin_op); + assert!( + right.layout.ty.is_integral() || + right.layout.ty.is_unsafe_ptr() || right.layout.ty.is_fn_ptr(), + "Unexpected RHS type {:?} for BinOp {:?}", right.layout.ty, bin_op); // Handle operations that support pointer values if left.to_scalar_ptr()?.is_ptr() ||