]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_const_eval/src/interpret/cast.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / compiler / rustc_const_eval / src / interpret / cast.rs
index fb484fba9fd066e77ed8f5edffe2210b0221dfd5..c97c31eb9dadfb98508feee369e9697a24dbdce8 100644 (file)
@@ -8,7 +8,7 @@ use rustc_middle::mir::CastKind;
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
-use rustc_target::abi::{Integer, Variants};
+use rustc_target::abi::Integer;
 use rustc_type_ir::sty::TyKind::*;
 
 use super::{
@@ -18,10 +18,10 @@ use super::{
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn cast(
         &mut self,
-        src: &OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::Provenance>,
         cast_kind: CastKind,
         cast_ty: Ty<'tcx>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         use rustc_middle::mir::CastKind::*;
         // FIXME: In which cases should we trigger UB when the source is uninit?
@@ -100,7 +100,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                             def_id,
                             substs,
                             ty::ClosureKind::FnOnce,
-                        );
+                        )
+                        .ok_or_else(|| err_inval!(TooGeneric))?;
                         let fn_ptr = self.create_fn_alloc_ptr(FnVal::Instance(instance));
                         self.write_pointer(fn_ptr, dest)?;
                     }
@@ -113,9 +114,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn misc_cast(
         &mut self,
-        src: &ImmTy<'tcx, M::PointerTag>,
+        src: &ImmTy<'tcx, M::Provenance>,
         cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
         use rustc_type_ir::sty::TyKind::*;
         trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty);
 
@@ -127,12 +128,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Float(FloatTy::F64) => {
                 return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, cast_ty).into());
             }
-            // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
-            // are represented as integers.
+            // 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_enum()
                     || src.layout.ty.is_integral()
                     || src.layout.ty.is_any_ptr(),
                 "Unexpected cast from type {:?}",
@@ -142,25 +141,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         // # First handle non-scalar source values.
 
-        // Handle cast from a ZST enum (0 or 1 variants).
-        match src.layout.variants {
-            Variants::Single { index } => {
-                if src.layout.abi.is_uninhabited() {
-                    // This is dead code, because an uninhabited enum is UB to
-                    // instantiate.
-                    throw_ub!(Unreachable);
-                }
-                if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
-                    assert!(src.layout.is_zst());
-                    let discr_layout = self.layout_of(discr.ty)?;
-
-                    let scalar = Scalar::from_uint(discr.val, discr_layout.layout.size());
-                    return Ok(self.cast_from_int_like(scalar, discr_layout, cast_ty)?.into());
-                }
-            }
-            Variants::Multiple { .. } => {}
-        }
-
         // 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)?;
@@ -173,7 +153,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 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::ScalarPair(data, _) => Ok(data.check_init()?.into()),
                     Immediate::Scalar(..) => span_bug!(
                         self.cur_span(),
                         "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
@@ -181,6 +161,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         src.layout.ty,
                         cast_ty
                     ),
+                    Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
                 };
             }
         }
@@ -192,26 +173,26 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn pointer_expose_address_cast(
         &mut self,
-        src: &ImmTy<'tcx, M::PointerTag>,
+        src: &ImmTy<'tcx, M::Provenance>,
         cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
         assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_));
         assert!(cast_ty.is_integral());
 
         let scalar = src.to_scalar()?;
-        let ptr = self.scalar_to_ptr(scalar)?;
+        let ptr = scalar.to_pointer(self)?;
         match ptr.into_pointer_or_addr() {
             Ok(ptr) => M::expose_ptr(self, ptr)?,
-            Err(_) => {} // do nothing, exposing an invalid pointer has no meaning
+            Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP.
         };
         Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
     }
 
     pub fn pointer_from_exposed_address_cast(
         &mut self,
-        src: &ImmTy<'tcx, M::PointerTag>,
+        src: &ImmTy<'tcx, M::Provenance>,
         cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
         assert!(src.layout.ty.is_integral());
         assert_matches!(cast_ty.kind(), ty::RawPtr(_));
 
@@ -227,10 +208,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn cast_from_int_like(
         &self,
-        scalar: Scalar<M::PointerTag>, // input value (there is no ScalarTy so we separate data+layout)
+        scalar: Scalar<M::Provenance>, // input value (there is no ScalarTy so we separate data+layout)
         src_layout: TyAndLayout<'tcx>,
         cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
         // Let's make sure v is sign-extended *if* it has a signed type.
         let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`.
 
@@ -264,9 +245,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         })
     }
 
-    fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::PointerTag>
+    fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance>
     where
-        F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>,
+        F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>,
     {
         use rustc_type_ir::sty::TyKind::*;
         match *dest_ty.kind() {
@@ -298,8 +279,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     fn unsize_into_ptr(
         &mut self,
-        src: &OpTy<'tcx, M::PointerTag>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::Provenance>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
         // The pointee types
         source_ty: Ty<'tcx>,
         cast_ty: Ty<'tcx>,
@@ -317,30 +298,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.write_immediate(val, dest)
             }
             (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
-                let val = self.read_immediate(src)?;
-                if data_a.principal_def_id() == data_b.principal_def_id() {
-                    return self.write_immediate(*val, dest);
-                }
-                // trait upcasting coercion
-                let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
-                    src_pointee_ty,
-                    dest_pointee_ty,
-                ));
-
-                if let Some(entry_idx) = vptr_entry_idx {
-                    let entry_idx = u64::try_from(entry_idx).unwrap();
-                    let (old_data, old_vptr) = val.to_scalar_pair()?;
-                    let old_vptr = self.scalar_to_ptr(old_vptr)?;
-                    let new_vptr = self
-                        .read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?;
-                    self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
-                } else {
-                    self.write_immediate(*val, dest)
+                let (old_data, old_vptr) = self.read_immediate(src)?.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() {
+                    throw_ub_format!("upcast on a pointer whose vtable does not match its type");
                 }
+                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, _)) => {
                 // Initial cast from sized to dyn trait
-                let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
+                let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?;
                 let ptr = self.read_immediate(src)?.to_scalar()?;
                 let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx);
                 self.write_immediate(val, dest)
@@ -354,9 +323,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     fn unsize_into(
         &mut self,
-        src: &OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::Provenance>,
         cast_ty: TyAndLayout<'tcx>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty);
         match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
@@ -366,22 +335,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
                 assert_eq!(def_a, def_b);
-                if def_a.is_box() || def_b.is_box() {
-                    if !def_a.is_box() || !def_b.is_box() {
-                        span_bug!(
-                            self.cur_span(),
-                            "invalid unsizing between {:?} -> {:?}",
-                            src.layout.ty,
-                            cast_ty.ty
-                        );
-                    }
-                    return self.unsize_into_ptr(
-                        src,
-                        dest,
-                        src.layout.ty.boxed_ty(),
-                        cast_ty.ty.boxed_ty(),
-                    );
-                }
 
                 // unsizing of generic struct with pointer fields
                 // Example: `Arc<T>` -> `Arc<Trait>`
@@ -394,7 +347,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     let src_field = self.operand_field(src, i)?;
                     let dst_field = self.place_field(dest, i)?;
                     if src_field.layout.ty == cast_ty_field.ty {
-                        self.copy_op(&src_field, &dst_field)?;
+                        self.copy_op(&src_field, &dst_field, /*allow_transmute*/ false)?;
                     } else {
                         self.unsize_into(&src_field, cast_ty_field, &dst_field)?;
                     }