]> git.lizzy.rs Git - rust.git/commitdiff
implement by-value object safety
authorRalf Jung <post@ralfj.de>
Sun, 7 Apr 2019 17:54:43 +0000 (19:54 +0200)
committerRalf Jung <post@ralfj.de>
Sun, 7 Apr 2019 18:04:44 +0000 (20:04 +0200)
src/librustc_mir/interpret/terminator.rs
src/librustc_mir/interpret/traits.rs

index 3bf0ff905ab7a1d59d8b62a31d612f9605498fe9..ba48a28fc83159d2b6b58243ca4202ab9a1c55c3 100644 (file)
@@ -407,9 +407,24 @@ fn eval_fn_call(
             }
             // cannot use the shim here, because that will only result in infinite recursion
             ty::InstanceDef::Virtual(_, idx) => {
+                let mut args = args.to_vec();
                 let ptr_size = self.pointer_size();
-                let ptr = self.deref_operand(args[0])?;
-                let vtable = ptr.vtable()?;
+                // We have to implement all "object safe receivers".  Currently we
+                // support built-in pointers (&, &mut, Box) as well as unsized-self.  We do
+                // not yet support custom self types.
+                // Also see librustc_codegen_llvm/abi.rs and librustc_codegen_llvm/mir/block.rs.
+                let receiver_place = match args[0].layout.ty.builtin_deref(true) {
+                    Some(_) => {
+                        // Built-in pointer.
+                        self.deref_operand(args[0])?
+                    }
+                    None => {
+                        // Unsized self.
+                        args[0].to_mem_place()
+                    }
+                };
+                // Find and consult vtable
+                let vtable = receiver_place.vtable()?;
                 self.memory.check_align(vtable.into(), self.tcx.data_layout.pointer_align.abi)?;
                 let fn_ptr = self.memory.get(vtable.alloc_id)?.read_ptr_sized(
                     self,
@@ -417,15 +432,16 @@ fn eval_fn_call(
                 )?.to_ptr()?;
                 let instance = self.memory.get_fn(fn_ptr)?;
 
-                // We have to patch the self argument, in particular get the layout
-                // expected by the actual function. Cannot just use "field 0" due to
-                // Box<self>.
-                let mut args = args.to_vec();
-                let pointee = args[0].layout.ty.builtin_deref(true).unwrap().ty;
-                let fake_fat_ptr_ty = self.tcx.mk_mut_ptr(pointee);
-                args[0] = OpTy::from(ImmTy { // strip vtable
-                    layout: self.layout_of(fake_fat_ptr_ty)?.field(self, 0)?,
-                    imm: Immediate::Scalar(ptr.ptr.into())
+                // `*mut receiver_place.layout.ty` is almost the layout that we
+                // want for args[0]: We have to project to field 0 because we want
+                // a thin pointer.
+                assert!(receiver_place.layout.is_unsized());
+                let receiver_ptr_ty = self.tcx.mk_mut_ptr(receiver_place.layout.ty);
+                let this_receiver_ptr = self.layout_of(receiver_ptr_ty)?.field(self, 0)?;
+                // Adjust receiver argument.
+                args[0] = OpTy::from(ImmTy {
+                    layout: this_receiver_ptr,
+                    imm: Immediate::Scalar(receiver_place.ptr.into())
                 });
                 trace!("Patched self operand to {:#?}", args[0]);
                 // recurse with concrete function
index cce6c95a31240f780feefccdc6e27f0fd87f3c9e..94e7f883f575be86b681538ffe1f6e79fac411a1 100644 (file)
@@ -3,7 +3,7 @@
 use rustc::ty::layout::{Size, Align, LayoutOf};
 use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic};
 
-use super::{InterpretCx, Machine, MemoryKind};
+use super::{InterpretCx, InterpError, Machine, MemoryKind};
 
 impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
     /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
@@ -76,7 +76,14 @@ pub fn get_vtable(
 
         for (i, method) in methods.iter().enumerate() {
             if let Some((def_id, substs)) = *method {
-                let instance = self.resolve(def_id, substs)?;
+                // resolve for vtable: insert thims where needed
+                let substs = self.subst_and_normalize_erasing_regions(substs)?;
+                let instance = ty::Instance::resolve_for_vtable(
+                    *self.tcx,
+                    self.param_env,
+                    def_id,
+                    substs,
+                ).ok_or_else(|| InterpError::TooGeneric)?;
                 let fn_ptr = self.memory.create_fn_alloc(instance).with_default_tag();
                 let method_ptr = vtable.offset(ptr_size * (3 + i as u64), self)?;
                 self.memory