diff --git a/src/error.rs b/src/error.rs index a465ad62b9d42..44179eafabbab 100644 --- a/src/error.rs +++ b/src/error.rs @@ -45,6 +45,7 @@ pub enum EvalError<'tcx> { VtableForArgumentlessMethod, ModifiedConstantMemory, AssumptionNotHeld, + InlineAsm, } 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::InlineAsm => + "cannot evaluate inline assembly", } } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index e6c4c4eb022f7..41dfa6806fb52 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; @@ -576,15 +577,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) => { @@ -667,7 +661,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } } - InlineAsm { .. } => unimplemented!(), + InlineAsm { .. } => return Err(EvalError::InlineAsm), } Ok(()) @@ -719,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))), } } @@ -889,19 +885,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 +1183,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> { @@ -1236,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) +} diff --git a/tests/compiletest.rs b/tests/compiletest.rs index e5058df95ea5d..e8f43bbbe019a 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(); @@ -92,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(); @@ -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); } 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); +}