]> git.lizzy.rs Git - rust.git/commitdiff
Merge remote-tracking branch 'origin/master' into function_pointers2
authorOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Mon, 13 Jun 2016 09:24:01 +0000 (11:24 +0200)
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Mon, 13 Jun 2016 09:24:01 +0000 (11:24 +0200)
src/interpreter/mod.rs
src/memory.rs
tests/compiletest.rs
tests/run-pass/heap.rs
tests/run-pass/sums.rs

index 251ebb768e0d6a3f7405c65fd1c2ae3e46a5fca3..1b0b416e0e12c1097500479fbfecf59a0487c9cf 100644 (file)
@@ -143,7 +143,7 @@ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
     pub fn alloc_ret_ptr(&mut self, output_ty: ty::FnOutput<'tcx>, substs: &'tcx Substs<'tcx>) -> Option<Pointer> {
         match output_ty {
             ty::FnConverging(ty) => {
-                let size = self.type_size(ty, substs);
+                let size = self.type_size_with_substs(ty, substs);
                 Some(self.memory.allocate(size))
             }
             ty::FnDiverging => None,
@@ -308,11 +308,19 @@ fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
         self.tcx.normalize_associated_type(&substituted)
     }
 
-    fn type_size(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize {
-        self.type_layout(ty, substs).size(&self.tcx.data_layout).bytes() as usize
+    fn type_size(&self, ty: Ty<'tcx>) -> usize {
+        self.type_size_with_substs(ty, self.substs())
     }
 
-    fn type_layout(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> &'tcx Layout {
+    fn type_size_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize {
+        self.type_layout_with_substs(ty, substs).size(&self.tcx.data_layout).bytes() as usize
+    }
+
+    fn type_layout(&self, ty: Ty<'tcx>) -> &'tcx Layout {
+        self.type_layout_with_substs(ty, self.substs())
+    }
+
+    fn type_layout_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> &'tcx Layout {
         // TODO(solson): Is this inefficient? Needs investigation.
         let ty = self.monomorphize(ty, substs);
 
@@ -335,7 +343,7 @@ pub fn push_stack_frame(&mut self, def_id: DefId, span: codemap::Span, mir: Cach
         ::log_settings::settings().indentation += 1;
 
         let locals: Vec<Pointer> = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| {
-            let size = self.type_size(ty, substs);
+            let size = self.type_size_with_substs(ty, substs);
             self.memory.allocate(size)
         }).collect();
 
@@ -378,7 +386,7 @@ fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>)
             SwitchInt { ref discr, ref values, ref targets, .. } => {
                 let discr_ptr = self.eval_lvalue(discr)?.to_ptr();
                 let discr_size = self
-                    .type_layout(self.lvalue_ty(discr), self.substs())
+                    .type_layout(self.lvalue_ty(discr))
                     .size(&self.tcx.data_layout)
                     .bytes() as usize;
                 let discr_val = self.memory.read_uint(discr_ptr, discr_size)?;
@@ -479,7 +487,7 @@ pub fn eval_fn_call(
                 let name = self.tcx.item_name(def_id).as_str();
                 match fn_ty.sig.0.output {
                     ty::FnConverging(ty) => {
-                        let size = self.type_size(ty, self.substs());
+                        let size = self.type_size(ty);
                         let ret = return_ptr.unwrap();
                         self.call_intrinsic(&name, substs, args, ret, size)
                     }
@@ -490,7 +498,7 @@ pub fn eval_fn_call(
             Abi::C => {
                 match fn_ty.sig.0.output {
                     ty::FnConverging(ty) => {
-                        let size = self.type_size(ty, self.substs());
+                        let size = self.type_size(ty);
                         self.call_c_abi(def_id, args, return_ptr.unwrap(), size)
                     }
                     ty::FnDiverging => unimplemented!(),
@@ -520,7 +528,7 @@ pub fn eval_fn_call(
                     let last_arg = args.last().unwrap();
                     let last = self.eval_operand(last_arg)?;
                     let last_ty = self.operand_ty(last_arg);
-                    let last_layout = self.type_layout(last_ty, self.substs());
+                    let last_layout = self.type_layout(last_ty);
                     match (&last_ty.sty, last_layout) {
                         (&ty::TyTuple(fields),
                          &Layout::Univariant { ref variant, .. }) => {
@@ -587,7 +595,7 @@ fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
 
         // Filling drop.
         // FIXME(solson): Trait objects (with no static size) probably get filled, too.
-        let size = self.type_size(ty, self.substs());
+        let size = self.type_size(ty);
         self.memory.drop_fill(ptr, size)?;
 
         Ok(())
@@ -595,7 +603,7 @@ fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
 
     fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<u64> {
         use rustc::ty::layout::Layout::*;
-        let adt_layout = self.type_layout(adt_ty, self.substs());
+        let adt_layout = self.type_layout(adt_ty);
 
         let discr_val = match *adt_layout {
             General { discr, .. } | CEnum { discr, .. } => {
@@ -648,7 +656,7 @@ fn call_intrinsic(
             // FIXME(solson): Handle different integer types correctly.
             "add_with_overflow" => {
                 let ty = *substs.types.get(subst::FnSpace, 0);
-                let size = self.type_size(ty, self.substs());
+                let size = self.type_size(ty);
                 let left = self.memory.read_int(args[0], size)?;
                 let right = self.memory.read_int(args[1], size)?;
                 let (n, overflowed) = unsafe {
@@ -662,7 +670,7 @@ fn call_intrinsic(
 
             "copy_nonoverlapping" => {
                 let elem_ty = *substs.types.get(subst::FnSpace, 0);
-                let elem_size = self.type_size(elem_ty, self.substs());
+                let elem_size = self.type_size(elem_ty);
                 let src = self.memory.read_ptr(args[0])?;
                 let dest = self.memory.read_ptr(args[1])?;
                 let count = self.memory.read_isize(args[2])?;
@@ -678,7 +686,7 @@ fn call_intrinsic(
 
             "forget" => {
                 let arg_ty = *substs.types.get(subst::FnSpace, 0);
-                let arg_size = self.type_size(arg_ty, self.substs());
+                let arg_size = self.type_size(arg_ty);
                 self.memory.drop_fill(args[0], arg_size)?;
             }
 
@@ -697,7 +705,7 @@ fn call_intrinsic(
             // FIXME(solson): Handle different integer types correctly.
             "mul_with_overflow" => {
                 let ty = *substs.types.get(subst::FnSpace, 0);
-                let size = self.type_size(ty, self.substs());
+                let size = self.type_size(ty);
                 let left = self.memory.read_int(args[0], size)?;
                 let right = self.memory.read_int(args[1], size)?;
                 let (n, overflowed) = unsafe {
@@ -709,7 +717,7 @@ fn call_intrinsic(
 
             "offset" => {
                 let pointee_ty = *substs.types.get(subst::FnSpace, 0);
-                let pointee_size = self.type_size(pointee_ty, self.substs()) as isize;
+                let pointee_size = self.type_size(pointee_ty) as isize;
                 let ptr_arg = args[0];
                 let offset = self.memory.read_isize(args[1])?;
 
@@ -730,7 +738,7 @@ fn call_intrinsic(
             // FIXME(solson): Handle different integer types correctly. Use primvals?
             "overflowing_sub" => {
                 let ty = *substs.types.get(subst::FnSpace, 0);
-                let size = self.type_size(ty, self.substs());
+                let size = self.type_size(ty);
                 let left = self.memory.read_int(args[0], size)?;
                 let right = self.memory.read_int(args[1], size)?;
                 let n = left.wrapping_sub(right);
@@ -739,20 +747,20 @@ fn call_intrinsic(
 
             "size_of" => {
                 let ty = *substs.types.get(subst::FnSpace, 0);
-                let size = self.type_size(ty, self.substs()) as u64;
+                let size = self.type_size(ty) as u64;
                 self.memory.write_uint(dest, size, dest_size)?;
             }
 
             "size_of_val" => {
                 let ty = *substs.types.get(subst::FnSpace, 0);
                 if self.type_is_sized(ty) {
-                    let size = self.type_size(ty, self.substs()) as u64;
+                    let size = self.type_size(ty) as u64;
                     self.memory.write_uint(dest, size, dest_size)?;
                 } else {
                     match ty.sty {
                         ty::TySlice(_) | ty::TyStr => {
                             let elem_ty = ty.sequence_element_type(self.tcx);
-                            let elem_size = self.type_size(elem_ty, self.substs()) as u64;
+                            let elem_size = self.type_size(elem_ty) as u64;
                             let ptr_size = self.memory.pointer_size as isize;
                             let n = self.memory.read_usize(args[0].offset(ptr_size))?;
                             self.memory.write_uint(dest, n * elem_size, dest_size)?;
@@ -831,7 +839,9 @@ fn call_c_abi(
                 self.memory.write_int(dest, result, dest_size)?;
             }
 
-            _ => return Err(EvalError::Unimplemented(format!("can't call C ABI function: {}", link_name))),
+            _ => {
+                return Err(EvalError::Unimplemented(format!("can't call C ABI function: {}", link_name)));
+            }
         }
 
         // Since we pushed no stack frame, the main loop will act
@@ -860,7 +870,7 @@ fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'
     {
         let dest = self.eval_lvalue(lvalue)?.to_ptr();
         let dest_ty = self.lvalue_ty(lvalue);
-        let dest_layout = self.type_layout(dest_ty, self.substs());
+        let dest_layout = self.type_layout(dest_ty);
 
         use rustc::mir::repr::Rvalue::*;
         match *rvalue {
@@ -897,7 +907,7 @@ fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'
 
                 // FIXME(solson): Find the result type size properly. Perhaps refactor out
                 // Projection calculations so we can do the equivalent of `dest.1` here.
-                let s = self.type_size(left_ty, self.substs());
+                let s = self.type_size(left_ty);
                 self.memory.write_bool(dest.offset(s as isize), false)?;
             }
 
@@ -919,7 +929,7 @@ fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'
 
                     Array { .. } => {
                         let elem_size = match dest_ty.sty {
-                            ty::TyArray(elem_ty, _) => self.type_size(elem_ty, self.substs()) as u64,
+                            ty::TyArray(elem_ty, _) => self.type_size(elem_ty) as u64,
                             _ => panic!("tried to assign {:?} to non-array type {:?}",
                                         kind, dest_ty),
                         };
@@ -997,7 +1007,7 @@ fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'
 
             Repeat(ref operand, _) => {
                 let (elem_size, length) = match dest_ty.sty {
-                    ty::TyArray(elem_ty, n) => (self.type_size(elem_ty, self.substs()), n),
+                    ty::TyArray(elem_ty, n) => (self.type_size(elem_ty), n),
                     _ => panic!("tried to assign array-repeat to non-array type {:?}", dest_ty),
                 };
 
@@ -1038,7 +1048,7 @@ fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'
             }
 
             Box(ty) => {
-                let size = self.type_size(ty, self.substs());
+                let size = self.type_size(ty);
                 let ptr = self.memory.allocate(size);
                 self.memory.write_ptr(dest, ptr)?;
             }
@@ -1065,9 +1075,23 @@ fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'
 
                     Misc => {
                         let src = self.eval_operand(operand)?;
+                        let src_ty = self.operand_ty(operand);
                         // FIXME(solson): Wrong for almost everything.
-                        let size = dest_layout.size(&self.tcx.data_layout).bytes() as usize;
-                        self.memory.copy(src, dest, size)?;
+                        warn!("misc cast from {:?} to {:?}", src_ty, dest_ty);
+                        let dest_size = self.type_size(dest_ty);
+                        let src_size = self.type_size(src_ty);
+
+                        // Hack to support fat pointer -> thin pointer casts to keep tests for
+                        // other things passing for now.
+                        let is_fat_ptr_cast = pointee_type(src_ty).map(|ty| {
+                            !self.type_is_sized(ty)
+                        }).unwrap_or(false);
+
+                        if dest_size == src_size || is_fat_ptr_cast {
+                            self.memory.copy(src, dest, dest_size)?;
+                        } else {
+                            return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue)));
+                        }
                     }
 
                     ReifyFnPointer => match self.operand_ty(operand).sty {
@@ -1139,7 +1163,7 @@ fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Ty<'tcx>>
     }
 
     fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Size> {
-        let layout = self.type_layout(ty, self.substs());
+        let layout = self.type_layout(ty);
 
         use rustc::ty::layout::Layout::*;
         match *layout {
@@ -1211,7 +1235,7 @@ fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<Lvalue> {
             Projection(ref proj) => {
                 let base = self.eval_lvalue(&proj.base)?;
                 let base_ty = self.lvalue_ty(&proj.base);
-                let base_layout = self.type_layout(base_ty, self.substs());
+                let base_layout = self.type_layout(base_ty);
 
                 use rustc::mir::repr::ProjectionElem::*;
                 match proj.elem {
@@ -1272,7 +1296,7 @@ fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<Lvalue> {
                     Index(ref operand) => {
                         let elem_size = match base_ty.sty {
                             ty::TyArray(elem_ty, _) |
-                            ty::TySlice(elem_ty) => self.type_size(elem_ty, self.substs()),
+                            ty::TySlice(elem_ty) => self.type_size(elem_ty),
                             _ => panic!("indexing expected an array or slice, got {:?}", base_ty),
                         };
                         let n_ptr = self.eval_operand(operand)?;
@@ -1298,7 +1322,7 @@ fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> {
     }
 
     fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
-        let size = self.type_size(ty, self.substs());
+        let size = self.type_size(ty);
         self.memory.copy(src, dest, size)?;
         if self.type_needs_drop(ty) {
             self.memory.drop_fill(src, size)?;
index d9999821e1b033f26a18734bc339961e77860ac9..ad6c60ef517c6bd100799b1f53ec5785cb63a07e 100644 (file)
@@ -99,17 +99,18 @@ pub fn reallocate(&mut self, ptr: Pointer, new_size: usize) -> EvalResult<()> {
             return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset)));
         }
 
-        let alloc = self.get_mut(ptr.alloc_id)?;
-        let size = alloc.bytes.len();
+        let size = self.get_mut(ptr.alloc_id)?.bytes.len();
+
         if new_size > size {
             let amount = new_size - size;
+            let alloc = self.get_mut(ptr.alloc_id)?;
             alloc.bytes.extend(iter::repeat(0).take(amount));
             alloc.undef_mask.grow(amount, false);
         } else if size > new_size {
-            return Err(EvalError::Unimplemented(format!("unimplemented allocation relocation (from {} to {})", size, new_size)));
-            // alloc.bytes.truncate(new_size);
-            // alloc.undef_mask.len = new_size;
-            // TODO: potentially remove relocations
+            self.clear_relocations(ptr.offset(new_size as isize), size - new_size)?;
+            let alloc = self.get_mut(ptr.alloc_id)?;
+            alloc.bytes.truncate(new_size);
+            alloc.undef_mask.truncate(new_size);
         }
 
         Ok(())
@@ -386,7 +387,7 @@ fn relocations(&self, ptr: Pointer, size: usize)
         -> EvalResult<btree_map::Range<usize, AllocId>>
     {
         let start = ptr.offset.saturating_sub(self.pointer_size - 1);
-        let end = start + size;
+        let end = ptr.offset + size;
         Ok(self.get(ptr.alloc_id)?.relocations.range(Included(&start), Excluded(&end)))
     }
 
@@ -535,11 +536,12 @@ fn grow(&mut self, amount: usize, new_state: bool) {
         self.len += amount;
         self.set_range_inbounds(start, start + amount, new_state);
     }
-}
 
-// fn uniform_block(state: bool) -> Block {
-//     if state { !0 } else { 0 }
-// }
+    fn truncate(&mut self, length: usize) {
+        self.len = length;
+        self.blocks.truncate(self.len / BLOCK_SIZE + 1);
+    }
+}
 
 fn bit_index(bits: usize) -> (usize, usize) {
     (bits / BLOCK_SIZE, bits % BLOCK_SIZE)
index 2fc1e615cff1965d9fd16b9f93234878c1ea2268..76b5b5f6e9638efe8628730e5b1574d3704002a7 100644 (file)
@@ -3,22 +3,32 @@
 use std::path::PathBuf;
 
 fn run_mode(mode: &'static str) {
+    // Disable rustc's new error fomatting. It breaks these tests.
+    std::env::remove_var("RUST_NEW_ERROR_FORMAT");
+
+    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
+    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
+    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
+    let sysroot = match (home, toolchain) {
+        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
+        _ => option_env!("RUST_SYSROOT")
+            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
+            .to_owned(),
+    };
+    let sysroot_flag = format!("--sysroot {}", sysroot);
+
     // FIXME: read directories in sysroot/lib/rustlib and generate the test targets from that
     let targets = &["x86_64-unknown-linux-gnu", "i686-unknown-linux-gnu"];
 
     for &target in targets {
         let mut config = compiletest::default_config();
+        config.host_rustcflags = Some(sysroot_flag.clone());
+        config.mode = mode.parse().expect("Invalid mode");
+        config.run_lib_path = format!("{}/lib/rustlib/{}/lib", sysroot, target);
         config.rustc_path = "target/debug/miri".into();
-        let path = std::env::var("RUST_SYSROOT").expect("env variable `RUST_SYSROOT` not set");
-        config.run_lib_path = format!("{}/lib/rustlib/{}/lib", path, target);
-        let path = format!("--sysroot {}", path);
-        config.target_rustcflags = Some(path.clone());
-        config.host_rustcflags = Some(path);
-        let cfg_mode = mode.parse().ok().expect("Invalid mode");
-
-        config.mode = cfg_mode;
         config.src_base = PathBuf::from(format!("tests/{}", mode));
         config.target = target.to_owned();
+        config.target_rustcflags = Some(sysroot_flag.clone());
         compiletest::run_tests(&config);
     }
 }
index f5aad1601c77d5ec329683e12773bcb1baa19ea6..a7175969efac52e8a6f26c75ff8d8a9813bf1ec9 100644 (file)
@@ -11,6 +11,26 @@ fn make_box_syntax() -> Box<(i16, i16)> {
     box (1, 2)
 }
 
+#[miri_run]
+fn allocate_reallocate() {
+    let mut s = String::new();
+
+    // 6 byte heap alloc (__rust_allocate)
+    s.push_str("foobar");
+    assert_eq!(s.len(), 6);
+    assert_eq!(s.capacity(), 6);
+
+    // heap size doubled to 12 (__rust_reallocate)
+    s.push_str("baz");
+    assert_eq!(s.len(), 9);
+    assert_eq!(s.capacity(), 12);
+
+    // heap size reduced to 9  (__rust_reallocate)
+    s.shrink_to_fit();
+    assert_eq!(s.len(), 9);
+    assert_eq!(s.capacity(), 9);
+}
+
 #[miri_run]
 fn main() {
     assert_eq!(*make_box(), (1, 2));
index 9b7ddb43b7c78242b033082e1137497e2d637c45..120c196abe9759ec63e5b78d2de8d9cdf4be136b 100644 (file)
@@ -55,7 +55,8 @@ fn two_nones() -> (Option<i16>, Option<i16>) {
     (None, None)
 }
 
-#[miri_run]
+// FIXME(solson): Casts inside PartialEq fails on 32-bit.
+#[cfg_attr(target_pointer_width = "64", miri_run)]
 fn main() {
     assert_eq!(two_nones(), (None, None));
     assert_eq!(match_opt_some(), 13);