]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_mir/src/interpret/cast.rs
Implement pointer casting.
[rust.git] / compiler / rustc_mir / src / interpret / cast.rs
index 514c1aa9646a063c28e50ac54ca11a1a8d755d01..cee4c2e30aa0973c019918601828caeed5a8f025 100644 (file)
@@ -269,12 +269,34 @@ fn unsize_into_ptr(
                     Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self);
                 self.write_immediate(val, dest)
             }
-            (&ty::Dynamic(..), &ty::Dynamic(..)) => {
-                // For now, upcasts are limited to changes in marker
-                // traits, and hence never actually require an actual
-                // change to the vtable.
+            (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
                 let val = self.read_immediate(src)?;
-                self.write_immediate(*val, dest)
+                if data_a.principal_def_id() == data_b.principal_def_id() {
+                    return self.write_immediate(*val, dest);
+                }
+                // trait upcasting coercion
+                let principal_a = data_a.principal().expect(
+                    "unsize_into_ptr: missing principal trait for trait upcasting coercion",
+                );
+                let principal_b = data_b.principal().expect(
+                    "unsize_into_ptr: missing principal trait for trait upcasting coercion",
+                );
+
+                let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
+                    principal_a.with_self_ty(*self.tcx, src_pointee_ty),
+                    principal_b.with_self_ty(*self.tcx, src_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)
+                }
             }
             (_, &ty::Dynamic(ref data, _)) => {
                 // Initial cast from sized to dyn trait