From 9e9d05e3ef7e32271c122b44438204e02326926a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 28 Sep 2016 14:53:11 +0200 Subject: [PATCH 1/6] run compile-fail tests after run-pass tests it's annoying when debugging miri to have compile-fail tests fail due to some temporary assertions or panics. --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index e5058df95ea5d..ad83ea005f92c 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -54,7 +54,6 @@ fn compile_test() { .expect("need to specify RUST_SYSROOT env var or use rustup or multirust") .to_owned(), }; - compile_fail(&sysroot); run_pass(); for_all_targets(&sysroot, |target| { let files = std::fs::read_dir("tests/run-pass").unwrap(); @@ -117,4 +116,5 @@ fn compile_test() { writeln!(stderr.lock(), "{} success, {} mir not found, {} crate not found, {} failed", success, mir_not_found, crate_not_found, failed).unwrap(); assert_eq!(failed, 0, "some tests failed"); }); + compile_fail(&sysroot); } From 73f6d6e418dfc3f00dff441db0176481d0dfaaad Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 28 Sep 2016 14:53:43 +0200 Subject: [PATCH 2/6] fix run-pass test error message parsing --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index ad83ea005f92c..e8f43bbbe019a 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -91,7 +91,7 @@ fn compile_test() { }, Ok(output) => { let output_err = std::str::from_utf8(&output.stderr).unwrap(); - if let Some(text) = output_err.splitn(2, "thread 'main' panicked at 'no mir for `").nth(1) { + if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) { mir_not_found += 1; let end = text.find('`').unwrap(); writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap(); From 1c18f6ddfa5a390184b67b66124b372c9d49eda2 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 28 Sep 2016 18:22:09 +0200 Subject: [PATCH 3/6] implement slice patterns --- src/interpreter/mod.rs | 51 +++++++++++++++++-------- tests/run-pass/issue-15080.rs | 33 ++++++++++++++++ tests/run-pass/issue-17877.rs | 24 ++++++++++++ tests/run-pass/vec-matching-fold.rs | 58 +++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 16 deletions(-) create mode 100644 tests/run-pass/issue-15080.rs create mode 100644 tests/run-pass/issue-17877.rs create mode 100644 tests/run-pass/vec-matching-fold.rs diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index e6c4c4eb022f7..cf43c33b5fcb2 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -576,15 +576,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Len(ref lvalue) => { let src = self.eval_lvalue(lvalue)?; let ty = self.lvalue_ty(lvalue); - match ty.sty { - ty::TyArray(_, n) => self.memory.write_usize(dest, n as u64)?, - ty::TySlice(_) => if let LvalueExtra::Length(len) = src.extra { - self.memory.write_usize(dest, len)?; - } else { - bug!("Rvalue::Len of a slice given non-slice pointer: {:?}", src); - }, - _ => bug!("Rvalue::Len expected array or slice, got {:?}", ty), - } + let (_, len) = src.elem_ty_and_len(ty); + self.memory.write_usize(dest, len)?; } Ref(_, _, ref lvalue) => { @@ -889,19 +882,34 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } Index(ref operand) => { - let elem_size = match base_ty.sty { - ty::TyArray(elem_ty, _) | - ty::TySlice(elem_ty) => self.type_size(elem_ty), - _ => bug!("indexing expected an array or slice, got {:?}", base_ty), - }; + let (elem_ty, len) = base.elem_ty_and_len(base_ty); + let elem_size = self.type_size(elem_ty); let n_ptr = self.eval_operand(operand)?; let usize = self.tcx.types.usize; let n = self.value_to_primval(n_ptr, usize)?.expect_uint("Projection::Index expected usize"); + assert!(n < len); base.ptr.offset(n as isize * elem_size as isize) } - ConstantIndex { .. } => unimplemented!(), - Subslice { .. } => unimplemented!(), + ConstantIndex { offset, min_length, from_end } => { + let (elem_ty, n) = base.elem_ty_and_len(base_ty); + let elem_size = self.type_size(elem_ty); + assert!(n >= min_length as u64); + if from_end { + base.ptr.offset((n as isize - offset as isize) * elem_size as isize) + } else { + base.ptr.offset(offset as isize * elem_size as isize) + } + }, + Subslice { from, to } => { + let (elem_ty, n) = base.elem_ty_and_len(base_ty); + let elem_size = self.type_size(elem_ty); + assert!((from as u64) <= n - (to as u64)); + return Ok(Lvalue { + ptr: base.ptr.offset(from as isize * elem_size as isize), + extra: LvalueExtra::Length(n - to as u64 - from as u64), + }) + }, } } }; @@ -1172,6 +1180,17 @@ impl Lvalue { assert_eq!(self.extra, LvalueExtra::None); self.ptr } + fn elem_ty_and_len<'tcx>(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { + match ty.sty { + ty::TyArray(elem, n) => (elem, n as u64), + ty::TySlice(elem) => if let LvalueExtra::Length(len) = self.extra { + (elem, len) + } else { + bug!("elem_ty_and_len called on a slice given non-slice lvalue: {:?}", self); + }, + _ => bug!("elem_ty_and_len expected array or slice, got {:?}", ty), + } + } } impl<'mir, 'tcx: 'mir> Deref for CachedMir<'mir, 'tcx> { diff --git a/tests/run-pass/issue-15080.rs b/tests/run-pass/issue-15080.rs new file mode 100644 index 0000000000000..cee0caeb465f5 --- /dev/null +++ b/tests/run-pass/issue-15080.rs @@ -0,0 +1,33 @@ +// 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. + + +#![feature(slice_patterns)] + +fn main() { + let mut x: &[_] = &[1, 2, 3, 4]; + + let mut result = vec!(); + loop { + x = match *x { + [1, n, 3, ref rest..] => { + result.push(n); + rest + } + [n, ref rest..] => { + result.push(n); + rest + } + [] => + break + } + } + assert_eq!(result, [2, 4]); +} diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs new file mode 100644 index 0000000000000..6c87e8d35fbf0 --- /dev/null +++ b/tests/run-pass/issue-17877.rs @@ -0,0 +1,24 @@ +// 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. + + +#![feature(slice_patterns)] + +fn main() { + assert_eq!(match [0u8; 1024] { + _ => 42_usize, + }, 42_usize); + + assert_eq!(match [0u8; 1024] { + [1, _..] => 0_usize, + [0, _..] => 1_usize, + _ => 2_usize + }, 1_usize); +} diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs new file mode 100644 index 0000000000000..ac80a4211ada6 --- /dev/null +++ b/tests/run-pass/vec-matching-fold.rs @@ -0,0 +1,58 @@ +// 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. + + +#![feature(advanced_slice_patterns)] +#![feature(slice_patterns)] + +use std::fmt::Debug; + +fn foldl(values: &[T], + initial: U, + mut function: F) + -> U where + U: Clone+Debug, T:Debug, + F: FnMut(U, &T) -> U, +{ match values { + &[ref head, ref tail..] => + foldl(tail, function(initial, head), function), + &[] => { + // FIXME: call guards + let res = initial.clone(); res + } + } +} + +fn foldr(values: &[T], + initial: U, + mut function: F) + -> U where + U: Clone, + F: FnMut(&T, U) -> U, +{ + match values { + &[ref head.., ref tail] => + foldr(head, function(tail, initial), function), + &[] => { + // FIXME: call guards + let res = initial.clone(); res + } + } +} + +pub fn main() { + let x = &[1, 2, 3, 4, 5]; + + let product = foldl(x, 1, |a, b| a * *b); + assert_eq!(product, 120); + + let sum = foldr(x, 0, |a, b| *a + b); + assert_eq!(sum, 15); +} From 51abf19e123b2c74114e44962f77e147e021ac4f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 28 Sep 2016 18:22:25 +0200 Subject: [PATCH 4/6] don't panic on asm! --- src/error.rs | 5 ++++- src/interpreter/mod.rs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index a465ad62b9d42..cee5d7d26906e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -45,6 +45,7 @@ pub enum EvalError<'tcx> { VtableForArgumentlessMethod, ModifiedConstantMemory, AssumptionNotHeld, + Assembler, } pub type EvalResult<'tcx, T> = Result>; @@ -102,7 +103,9 @@ impl<'tcx> Error for EvalError<'tcx> { EvalError::ModifiedConstantMemory => "tried to modify constant memory", EvalError::AssumptionNotHeld => - "`assume` argument was false" + "`assume` argument was false", + EvalError::Assembler => + "cannot evaluate assembler code", } } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index cf43c33b5fcb2..c9d18507337d6 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -660,7 +660,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } } - InlineAsm { .. } => unimplemented!(), + InlineAsm { .. } => return Err(EvalError::Assembler), } Ok(()) From 787feaad4b9d03805e2e6aa5a4266cbd5b140f85 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 28 Sep 2016 18:22:53 +0200 Subject: [PATCH 5/6] allow tuple field indexing into anonymous tuples --- src/interpreter/mod.rs | 9 +++- .../send-is-not-static-par-for.rs | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/send-is-not-static-par-for.rs diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index c9d18507337d6..70b7806706fc8 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -1,5 +1,6 @@ use rustc::middle::const_val::ConstVal; use rustc::hir::def_id::DefId; +use rustc::hir::map::definitions::DefPathData; use rustc::mir::mir_map::MirMap; use rustc::mir::repr as mir; use rustc::traits::Reveal; @@ -712,13 +713,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs)) } + ty::TyTuple(fields) => Ok(fields[field_index]), + ty::TyRef(_, ty::TypeAndMut { ty, .. }) | ty::TyRawPtr(ty::TypeAndMut { ty, .. }) | ty::TyBox(ty) => { assert_eq!(field_index, 0); Ok(ty) } - _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}", ty))), + _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, {:?}", ty, ty.sty))), } } @@ -1255,6 +1258,10 @@ fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) { }; let mut err = tcx.sess.struct_span_err(span, &e.to_string()); for &Frame { def_id, substs, span, .. } in ecx.stack().iter().rev() { + if tcx.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr { + err.span_note(span, "inside call to closure"); + continue; + } // FIXME(solson): Find a way to do this without this Display impl hack. use rustc::util::ppaux; use std::fmt; diff --git a/tests/compile-fail/send-is-not-static-par-for.rs b/tests/compile-fail/send-is-not-static-par-for.rs new file mode 100644 index 0000000000000..bee05ecd7fae3 --- /dev/null +++ b/tests/compile-fail/send-is-not-static-par-for.rs @@ -0,0 +1,43 @@ +// Copyright 2015 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. + +//error-pattern: no mir for `std::panicking::panicking` + +use std::sync::Mutex; + +fn par_for(iter: I, f: F) + where I: Iterator, + I::Item: Send, + F: Fn(I::Item) + Sync +{ + for item in iter { + f(item) + } +} + +fn sum(x: &[i32]) { + let sum_lengths = Mutex::new(0); + par_for(x.windows(4), |x| { + *sum_lengths.lock().unwrap() += x.len() + }); + + assert_eq!(*sum_lengths.lock().unwrap(), (x.len() - 3) * 4); +} + +fn main() { + let mut elements = [0; 20]; + + // iterators over references into this stack frame + par_for(elements.iter_mut().enumerate(), |(i, x)| { + *x = i as i32 + }); + + sum(&elements) +} From 870bb4d862ee3c5b23cb428e7a697a13917ec8d8 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Wed, 28 Sep 2016 11:48:43 -0600 Subject: [PATCH 6/6] Reword inline assembly error. --- src/error.rs | 6 +++--- src/interpreter/mod.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/error.rs b/src/error.rs index cee5d7d26906e..44179eafabbab 100644 --- a/src/error.rs +++ b/src/error.rs @@ -45,7 +45,7 @@ pub enum EvalError<'tcx> { VtableForArgumentlessMethod, ModifiedConstantMemory, AssumptionNotHeld, - Assembler, + InlineAsm, } pub type EvalResult<'tcx, T> = Result>; @@ -104,8 +104,8 @@ impl<'tcx> Error for EvalError<'tcx> { "tried to modify constant memory", EvalError::AssumptionNotHeld => "`assume` argument was false", - EvalError::Assembler => - "cannot evaluate assembler code", + EvalError::InlineAsm => + "cannot evaluate inline assembly", } } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 70b7806706fc8..41dfa6806fb52 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -661,7 +661,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } } - InlineAsm { .. } => return Err(EvalError::Assembler), + InlineAsm { .. } => return Err(EvalError::InlineAsm), } Ok(())