diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index e381ebdba69..9e8c2996d26 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -579,15 +579,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ref(_, _, ref lvalue) => { let lv = self.eval_lvalue(lvalue)?; - let (ptr, extra) = self.get_fat_ptr(dest); - self.memory.write_ptr(ptr, lv.ptr)?; match lv.extra { - LvalueExtra::None => {}, + LvalueExtra::None => self.memory.write_ptr(dest, lv.ptr)?, LvalueExtra::Length(len) => { - self.memory.write_usize(extra, len)?; + self.memory.write_primval(dest, PrimVal::SlicePtr(lv.ptr, len))?; } LvalueExtra::Vtable(ptr) => { - self.memory.write_ptr(extra, ptr)?; + self.memory.write_primval(dest, PrimVal::VtablePtr(lv.ptr, ptr))?; }, LvalueExtra::DowncastVariant(..) => bug!("attempted to take a reference to an enum downcast lvalue"), @@ -902,21 +900,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }, Deref => { - let pointee_ty = pointee_type(base_ty).expect("Deref of non-pointer"); - let pointee_ty = self.tcx.struct_tail(pointee_ty); - let ptr = self.memory.read_ptr(base.ptr)?; - let extra = match pointee_ty.sty { - ty::TySlice(_) | ty::TyStr => { - let (_, extra) = self.get_fat_ptr(base.ptr); - let len = self.memory.read_usize(extra)?; - LvalueExtra::Length(len) - } - ty::TyTrait(_) => { - let (_, extra) = self.get_fat_ptr(base.ptr); - let vtable = self.memory.read_ptr(extra)?; - LvalueExtra::Vtable(vtable) - }, - _ => LvalueExtra::None, + let (ptr, extra) = match self.read_primval(base.ptr, base_ty)? { + PrimVal::SlicePtr(ptr, n) => (ptr, LvalueExtra::Length(n)), + PrimVal::VtablePtr(ptr, vptr) => (ptr, LvalueExtra::Vtable(vptr)), + PrimVal::Ptr(ptr) => (ptr, LvalueExtra::None), + _ => bug!("can't deref non pointer types"), }; return Ok(Lvalue { ptr: ptr, extra: extra }); } @@ -942,12 +930,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok(Lvalue { ptr: ptr, extra: LvalueExtra::None }) } - fn get_fat_ptr(&self, ptr: Pointer) -> (Pointer, Pointer) { - assert_eq!(layout::FAT_PTR_ADDR, 0); - assert_eq!(layout::FAT_PTR_EXTRA, 1); - (ptr, ptr.offset(self.memory.pointer_size() as isize)) - } - fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> { self.monomorphize(lvalue.ty(&self.mir(), self.tcx).to_ty(self.tcx), self.substs()) } @@ -1038,12 +1020,21 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { PrimVal::FnPtr(self.memory.create_fn_ptr(def_id, substs, fn_ty)) }, &ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::FnPtr)?, + &ty::TyBox(ty) | &ty::TyRef(_, ty::TypeAndMut { ty, .. }) | &ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => { + let p = self.memory.read_ptr(ptr)?; if self.type_is_sized(ty) { - PrimVal::Ptr(self.memory.read_ptr(ptr)?) + PrimVal::Ptr(p) } else { - bug!("primitive read of fat pointer type: {:?}", ty); + // FIXME: extract the offset to the tail field for `Box<(i64, i32, [u8])>` + let extra = ptr.offset(self.memory.pointer_size() as isize); + match self.tcx.struct_tail(ty).sty { + ty::TyTrait(..) => PrimVal::VtablePtr(p, self.memory.read_ptr(extra)?), + ty::TySlice(..) | + ty::TyStr => PrimVal::SlicePtr(p, self.memory.read_usize(extra)?), + _ => bug!("unsized primval ptr read from {:?}", ty), + } } } diff --git a/tests/run-pass/dst-struct.rs b/tests/run-pass/dst-struct.rs new file mode 100644 index 00000000000..932b571eccd --- /dev/null +++ b/tests/run-pass/dst-struct.rs @@ -0,0 +1,134 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +#![allow(unused_features)] +#![feature(box_syntax)] + +struct Fat { + f1: isize, + f2: &'static str, + ptr: T +} + +// x is a fat pointer +fn foo(x: &Fat<[isize]>) { + let y = &x.ptr; + assert_eq!(x.ptr.len(), 3); + assert_eq!(y[0], 1); + assert_eq!(x.ptr[1], 2); + assert_eq!(x.f1, 5); + assert_eq!(x.f2, "some str"); +} + +fn foo2(x: &Fat<[T]>) { + let y = &x.ptr; + let bar = Bar; + assert_eq!(x.ptr.len(), 3); + assert_eq!(y[0].to_bar(), bar); + assert_eq!(x.ptr[1].to_bar(), bar); + assert_eq!(x.f1, 5); + assert_eq!(x.f2, "some str"); +} + +fn foo3(x: &Fat>) { + let y = &x.ptr.ptr; + assert_eq!(x.f1, 5); + assert_eq!(x.f2, "some str"); + assert_eq!(x.ptr.f1, 8); + assert_eq!(x.ptr.f2, "deep str"); + assert_eq!(x.ptr.ptr.len(), 3); + assert_eq!(y[0], 1); + assert_eq!(x.ptr.ptr[1], 2); +} + + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct Bar; + +trait ToBar { + fn to_bar(&self) -> Bar; +} + +impl ToBar for Bar { + fn to_bar(&self) -> Bar { + *self + } +} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&f1); + let f2 = &f1; + foo(f2); + let f3: &Fat<[isize]> = f2; + foo(f3); + let f4: &Fat<[isize]> = &f1; + foo(f4); + let f5: &Fat<[isize]> = &Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(f5); + + // With a vec of Bars. + let bar = Bar; + let f1 = Fat { f1: 5, f2: "some str", ptr: [bar, bar, bar] }; + foo2(&f1); + let f2 = &f1; + foo2(f2); + let f3: &Fat<[Bar]> = f2; + foo2(f3); + let f4: &Fat<[Bar]> = &f1; + foo2(f4); + let f5: &Fat<[Bar]> = &Fat { f1: 5, f2: "some str", ptr: [bar, bar, bar] }; + foo2(f5); + + // Assignment. + let f5: &mut Fat<[isize]> = &mut Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + f5.ptr[1] = 34; + assert_eq!(f5.ptr[0], 1); + assert_eq!(f5.ptr[1], 34); + assert_eq!(f5.ptr[2], 3); + + // Zero size vec. + let f5: &Fat<[isize]> = &Fat { f1: 5, f2: "some str", ptr: [] }; + assert!(f5.ptr.is_empty()); + let f5: &Fat<[Bar]> = &Fat { f1: 5, f2: "some str", ptr: [] }; + assert!(f5.ptr.is_empty()); + + // Deeply nested. + let f1 = Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; + foo3(&f1); + let f2 = &f1; + foo3(f2); + let f3: &Fat> = f2; + foo3(f3); + let f4: &Fat> = &f1; + foo3(f4); + let f5: &Fat> = + &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; + foo3(f5); + + // Box. + let f1 = Box::new([1, 2, 3]); + assert_eq!((*f1)[1], 2); + let f2: Box<[isize]> = f1; + assert_eq!((*f2)[1], 2); + + // Nested Box. + let f1 : Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&*f1); + let f2 : Box> = f1; + foo(&*f2); + + // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. + let f3 : Box> = + Box::>::new(Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }); + foo(&*f3); +}