diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 8b4fce158de46..a6f817a89624c 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1446,13 +1446,12 @@ impl IntoIterator for Vec { #[inline] fn into_iter(mut self) -> IntoIter { unsafe { - let ptr = self.as_mut_ptr(); - assume(!ptr.is_null()); - let begin = ptr as *const T; + let begin = self.as_mut_ptr(); + assume(!begin.is_null()); let end = if mem::size_of::() == 0 { - arith_offset(ptr as *const i8, self.len() as isize) as *const T + arith_offset(begin as *const i8, self.len() as isize) as *const T } else { - ptr.offset(self.len() as isize) as *const T + begin.offset(self.len() as isize) as *const T }; let buf = ptr::read(&self.buf); mem::forget(self); @@ -1710,10 +1709,52 @@ impl<'a, T> FromIterator for Cow<'a, [T]> where T: Clone { #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { _buf: RawVec, - ptr: *const T, + ptr: *mut T, end: *const T, } +impl IntoIter { + /// Returns the remaining items of this iterator as a slice. + /// + /// # Examples + /// + /// ```rust + /// # #![feature(vec_into_iter_as_slice)] + /// let vec = vec!['a', 'b', 'c']; + /// let mut into_iter = vec.into_iter(); + /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + /// let _ = into_iter.next().unwrap(); + /// assert_eq!(into_iter.as_slice(), &['b', 'c']); + /// ``` + #[unstable(feature = "vec_into_iter_as_slice", issue = "35601")] + pub fn as_slice(&self) -> &[T] { + unsafe { + slice::from_raw_parts(self.ptr, self.len()) + } + } + + /// Returns the remaining items of this iterator as a mutable slice. + /// + /// # Examples + /// + /// ```rust + /// # #![feature(vec_into_iter_as_slice)] + /// let vec = vec!['a', 'b', 'c']; + /// let mut into_iter = vec.into_iter(); + /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + /// into_iter.as_mut_slice()[2] = 'z'; + /// assert_eq!(into_iter.next().unwrap(), 'a'); + /// assert_eq!(into_iter.next().unwrap(), 'b'); + /// assert_eq!(into_iter.next().unwrap(), 'z'); + /// ``` + #[unstable(feature = "vec_into_iter_as_slice", issue = "35601")] + pub fn as_mut_slice(&self) -> &mut [T] { + unsafe { + slice::from_raw_parts_mut(self.ptr, self.len()) + } + } +} + #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Send for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1726,14 +1767,14 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option { unsafe { - if self.ptr == self.end { + if self.ptr as *const _ == self.end { None } else { if mem::size_of::() == 0 { // purposefully don't use 'ptr.offset' because for // vectors with 0-size elements this would return the // same pointer. - self.ptr = arith_offset(self.ptr as *const i8, 1) as *const T; + self.ptr = arith_offset(self.ptr as *const i8, 1) as *mut T; // Use a non-null pointer value Some(ptr::read(EMPTY as *mut T)) @@ -1776,7 +1817,7 @@ impl DoubleEndedIterator for IntoIter { } else { if mem::size_of::() == 0 { // See above for why 'ptr.offset' isn't used - self.end = arith_offset(self.end as *const i8, -1) as *const T; + self.end = arith_offset(self.end as *const i8, -1) as *mut T; // Use a non-null pointer value Some(ptr::read(EMPTY as *mut T)) @@ -1796,9 +1837,7 @@ impl ExactSizeIterator for IntoIter {} #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] impl Clone for IntoIter { fn clone(&self) -> IntoIter { - unsafe { - slice::from_raw_parts(self.ptr, self.len()).to_owned().into_iter() - } + self.as_slice().to_owned().into_iter() } } diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 8ae63808f2740..ab3231b2b9955 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -28,6 +28,7 @@ #![feature(unboxed_closures)] #![feature(unicode)] #![feature(vec_deque_contains)] +#![feature(vec_into_iter_as_slice)] extern crate collections; extern crate test; diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index 7a6bd958a5f8c..9556174bd2294 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -478,6 +478,29 @@ fn test_split_off() { assert_eq!(vec2, [5, 6]); } +#[test] +fn test_into_iter_as_slice() { + let vec = vec!['a', 'b', 'c']; + let mut into_iter = vec.into_iter(); + assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + let _ = into_iter.next().unwrap(); + assert_eq!(into_iter.as_slice(), &['b', 'c']); + let _ = into_iter.next().unwrap(); + let _ = into_iter.next().unwrap(); + assert_eq!(into_iter.as_slice(), &[]); +} + +#[test] +fn test_into_iter_as_mut_slice() { + let vec = vec!['a', 'b', 'c']; + let mut into_iter = vec.into_iter(); + assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + into_iter.as_mut_slice()[0] = 'x'; + into_iter.as_mut_slice()[1] = 'y'; + assert_eq!(into_iter.next().unwrap(), 'x'); + assert_eq!(into_iter.as_slice(), &['y', 'c']); +} + #[test] fn test_into_iter_count() { assert_eq!(vec![1, 2, 3].into_iter().count(), 3); diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 08614ca253be5..51b9d7b9f53e7 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -1233,3 +1233,14 @@ impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> { type Item = BasicBlock; type Iter = IntoIter; } + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)] +pub struct Location { + /// the location is within this block + pub block: BasicBlock, + + /// the location is the start of the this statement; or, if `statement_index` + /// == num-statements, then the start of the terminator. + pub statement_index: usize, +} + diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index d44f00ed2cbe2..3fc3fd2b51324 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -105,60 +105,70 @@ macro_rules! make_mir_visitor { fn visit_statement(&mut self, block: BasicBlock, - statement: & $($mutability)* Statement<'tcx>) { - self.super_statement(block, statement); + statement: & $($mutability)* Statement<'tcx>, + location: Location) { + self.super_statement(block, statement, location); } fn visit_assign(&mut self, block: BasicBlock, lvalue: & $($mutability)* Lvalue<'tcx>, - rvalue: & $($mutability)* Rvalue<'tcx>) { - self.super_assign(block, lvalue, rvalue); + rvalue: & $($mutability)* Rvalue<'tcx>, + location: Location) { + self.super_assign(block, lvalue, rvalue, location); } fn visit_terminator(&mut self, block: BasicBlock, - terminator: & $($mutability)* Terminator<'tcx>) { - self.super_terminator(block, terminator); + terminator: & $($mutability)* Terminator<'tcx>, + location: Location) { + self.super_terminator(block, terminator, location); } fn visit_terminator_kind(&mut self, block: BasicBlock, - kind: & $($mutability)* TerminatorKind<'tcx>) { - self.super_terminator_kind(block, kind); + kind: & $($mutability)* TerminatorKind<'tcx>, + location: Location) { + self.super_terminator_kind(block, kind, location); } fn visit_assert_message(&mut self, - msg: & $($mutability)* AssertMessage<'tcx>) { - self.super_assert_message(msg); + msg: & $($mutability)* AssertMessage<'tcx>, + location: Location) { + self.super_assert_message(msg, location); } fn visit_rvalue(&mut self, - rvalue: & $($mutability)* Rvalue<'tcx>) { - self.super_rvalue(rvalue); + rvalue: & $($mutability)* Rvalue<'tcx>, + location: Location) { + self.super_rvalue(rvalue, location); } fn visit_operand(&mut self, - operand: & $($mutability)* Operand<'tcx>) { - self.super_operand(operand); + operand: & $($mutability)* Operand<'tcx>, + location: Location) { + self.super_operand(operand, location); } fn visit_lvalue(&mut self, lvalue: & $($mutability)* Lvalue<'tcx>, - context: LvalueContext) { - self.super_lvalue(lvalue, context); + context: LvalueContext, + location: Location) { + self.super_lvalue(lvalue, context, location); } fn visit_projection(&mut self, lvalue: & $($mutability)* LvalueProjection<'tcx>, - context: LvalueContext) { - self.super_projection(lvalue, context); + context: LvalueContext, + location: Location) { + self.super_projection(lvalue, context, location); } fn visit_projection_elem(&mut self, lvalue: & $($mutability)* LvalueElem<'tcx>, - context: LvalueContext) { - self.super_projection_elem(lvalue, context); + context: LvalueContext, + location: Location) { + self.super_projection_elem(lvalue, context, location); } fn visit_branch(&mut self, @@ -168,17 +178,20 @@ macro_rules! make_mir_visitor { } fn visit_constant(&mut self, - constant: & $($mutability)* Constant<'tcx>) { - self.super_constant(constant); + constant: & $($mutability)* Constant<'tcx>, + location: Location) { + self.super_constant(constant, location); } fn visit_literal(&mut self, - literal: & $($mutability)* Literal<'tcx>) { - self.super_literal(literal); + literal: & $($mutability)* Literal<'tcx>, + location: Location) { + self.super_literal(literal, location); } fn visit_def_id(&mut self, - def_id: & $($mutability)* DefId) { + def_id: & $($mutability)* DefId, + _: Location) { self.super_def_id(def_id); } @@ -213,18 +226,21 @@ macro_rules! make_mir_visitor { } fn visit_const_val(&mut self, - const_val: & $($mutability)* ConstVal) { + const_val: & $($mutability)* ConstVal, + _: Location) { self.super_const_val(const_val); } fn visit_const_usize(&mut self, - const_usize: & $($mutability)* ConstUsize) { + const_usize: & $($mutability)* ConstUsize, + _: Location) { self.super_const_usize(const_usize); } fn visit_typed_const_val(&mut self, - val: & $($mutability)* TypedConstVal<'tcx>) { - self.super_typed_const_val(val); + val: & $($mutability)* TypedConstVal<'tcx>, + location: Location) { + self.super_typed_const_val(val, location); } fn visit_var_decl(&mut self, @@ -287,12 +303,16 @@ macro_rules! make_mir_visitor { is_cleanup: _ } = *data; + let mut index = 0; for statement in statements { - self.visit_statement(block, statement); + let location = Location { block: block, statement_index: index }; + self.visit_statement(block, statement, location); + index += 1; } if let Some(ref $($mutability)* terminator) = *terminator { - self.visit_terminator(block, terminator); + let location = Location { block: block, statement_index: index }; + self.visit_terminator(block, terminator, location); } } @@ -311,7 +331,8 @@ macro_rules! make_mir_visitor { fn super_statement(&mut self, block: BasicBlock, - statement: & $($mutability)* Statement<'tcx>) { + statement: & $($mutability)* Statement<'tcx>, + location: Location) { let Statement { ref $($mutability)* source_info, ref $($mutability)* kind, @@ -321,7 +342,7 @@ macro_rules! make_mir_visitor { match *kind { StatementKind::Assign(ref $($mutability)* lvalue, ref $($mutability)* rvalue) => { - self.visit_assign(block, lvalue, rvalue); + self.visit_assign(block, lvalue, rvalue, location); } StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => { self.visit_lvalue(lvalue, LvalueContext::Store); @@ -332,26 +353,29 @@ macro_rules! make_mir_visitor { fn super_assign(&mut self, _block: BasicBlock, lvalue: &$($mutability)* Lvalue<'tcx>, - rvalue: &$($mutability)* Rvalue<'tcx>) { - self.visit_lvalue(lvalue, LvalueContext::Store); - self.visit_rvalue(rvalue); + rvalue: &$($mutability)* Rvalue<'tcx>, + location: Location) { + self.visit_lvalue(lvalue, LvalueContext::Store, location); + self.visit_rvalue(rvalue, location); } fn super_terminator(&mut self, block: BasicBlock, - terminator: &$($mutability)* Terminator<'tcx>) { + terminator: &$($mutability)* Terminator<'tcx>, + location: Location) { let Terminator { ref $($mutability)* source_info, ref $($mutability)* kind, } = *terminator; self.visit_source_info(source_info); - self.visit_terminator_kind(block, kind); + self.visit_terminator_kind(block, kind, location); } fn super_terminator_kind(&mut self, block: BasicBlock, - kind: & $($mutability)* TerminatorKind<'tcx>) { + kind: & $($mutability)* TerminatorKind<'tcx>, + source_location: Location) { match *kind { TerminatorKind::Goto { target } => { self.visit_branch(block, target); @@ -359,7 +383,7 @@ macro_rules! make_mir_visitor { TerminatorKind::If { ref $($mutability)* cond, ref $($mutability)* targets } => { - self.visit_operand(cond); + self.visit_operand(cond, source_location); for &target in targets.as_slice() { self.visit_branch(block, target); } @@ -368,7 +392,7 @@ macro_rules! make_mir_visitor { TerminatorKind::Switch { ref $($mutability)* discr, adt_def: _, ref targets } => { - self.visit_lvalue(discr, LvalueContext::Inspect); + self.visit_lvalue(discr, LvalueContext::Inspect, source_location); for &target in targets { self.visit_branch(block, target); } @@ -378,10 +402,10 @@ macro_rules! make_mir_visitor { ref $($mutability)* switch_ty, ref $($mutability)* values, ref targets } => { - self.visit_lvalue(discr, LvalueContext::Inspect); + self.visit_lvalue(discr, LvalueContext::Inspect, source_location); self.visit_ty(switch_ty); for value in values { - self.visit_const_val(value); + self.visit_const_val(value, source_location); } for &target in targets { self.visit_branch(block, target); @@ -396,7 +420,7 @@ macro_rules! make_mir_visitor { TerminatorKind::Drop { ref $($mutability)* location, target, unwind } => { - self.visit_lvalue(location, LvalueContext::Drop); + self.visit_lvalue(location, LvalueContext::Drop, source_location); self.visit_branch(block, target); unwind.map(|t| self.visit_branch(block, t)); } @@ -405,8 +429,8 @@ macro_rules! make_mir_visitor { ref $($mutability)* value, target, unwind } => { - self.visit_lvalue(location, LvalueContext::Drop); - self.visit_operand(value); + self.visit_lvalue(location, LvalueContext::Drop, source_location); + self.visit_operand(value, source_location); self.visit_branch(block, target); unwind.map(|t| self.visit_branch(block, t)); } @@ -415,12 +439,12 @@ macro_rules! make_mir_visitor { ref $($mutability)* args, ref $($mutability)* destination, cleanup } => { - self.visit_operand(func); + self.visit_operand(func, source_location); for arg in args { - self.visit_operand(arg); + self.visit_operand(arg, source_location); } if let Some((ref $($mutability)* destination, target)) = *destination { - self.visit_lvalue(destination, LvalueContext::Call); + self.visit_lvalue(destination, LvalueContext::Call, source_location); self.visit_branch(block, target); } cleanup.map(|t| self.visit_branch(block, t)); @@ -431,8 +455,8 @@ macro_rules! make_mir_visitor { ref $($mutability)* msg, target, cleanup } => { - self.visit_operand(cond); - self.visit_assert_message(msg); + self.visit_operand(cond, source_location); + self.visit_assert_message(msg, source_location); self.visit_branch(block, target); cleanup.map(|t| self.visit_branch(block, t)); } @@ -440,47 +464,49 @@ macro_rules! make_mir_visitor { } fn super_assert_message(&mut self, - msg: & $($mutability)* AssertMessage<'tcx>) { + msg: & $($mutability)* AssertMessage<'tcx>, + location: Location) { match *msg { AssertMessage::BoundsCheck { ref $($mutability)* len, ref $($mutability)* index } => { - self.visit_operand(len); - self.visit_operand(index); + self.visit_operand(len, location); + self.visit_operand(index, location); } AssertMessage::Math(_) => {} } } fn super_rvalue(&mut self, - rvalue: & $($mutability)* Rvalue<'tcx>) { + rvalue: & $($mutability)* Rvalue<'tcx>, + location: Location) { match *rvalue { Rvalue::Use(ref $($mutability)* operand) => { - self.visit_operand(operand); + self.visit_operand(operand, location); } Rvalue::Repeat(ref $($mutability)* value, ref $($mutability)* typed_const_val) => { - self.visit_operand(value); - self.visit_typed_const_val(typed_const_val); + self.visit_operand(value, location); + self.visit_typed_const_val(typed_const_val, location); } Rvalue::Ref(r, bk, ref $($mutability)* path) => { self.visit_lvalue(path, LvalueContext::Borrow { region: r, kind: bk - }); + }, location); } Rvalue::Len(ref $($mutability)* path) => { - self.visit_lvalue(path, LvalueContext::Inspect); + self.visit_lvalue(path, LvalueContext::Inspect, location); } Rvalue::Cast(_cast_kind, ref $($mutability)* operand, ref $($mutability)* ty) => { - self.visit_operand(operand); + self.visit_operand(operand, location); self.visit_ty(ty); } @@ -490,12 +516,12 @@ macro_rules! make_mir_visitor { Rvalue::CheckedBinaryOp(_bin_op, ref $($mutability)* lhs, ref $($mutability)* rhs) => { - self.visit_operand(lhs); - self.visit_operand(rhs); + self.visit_operand(lhs, location); + self.visit_operand(rhs, location); } Rvalue::UnaryOp(_un_op, ref $($mutability)* op) => { - self.visit_operand(op); + self.visit_operand(op, location); } Rvalue::Box(ref $($mutability)* ty) => { @@ -516,13 +542,13 @@ macro_rules! make_mir_visitor { } AggregateKind::Closure(ref $($mutability)* def_id, ref $($mutability)* closure_substs) => { - self.visit_def_id(def_id); + self.visit_def_id(def_id, location); self.visit_closure_substs(closure_substs); } } for operand in operands { - self.visit_operand(operand); + self.visit_operand(operand, location); } } @@ -530,30 +556,32 @@ macro_rules! make_mir_visitor { ref $($mutability)* inputs, asm: _ } => { for output in & $($mutability)* outputs[..] { - self.visit_lvalue(output, LvalueContext::Store); + self.visit_lvalue(output, LvalueContext::Store, location); } for input in & $($mutability)* inputs[..] { - self.visit_operand(input); + self.visit_operand(input, location); } } } } fn super_operand(&mut self, - operand: & $($mutability)* Operand<'tcx>) { + operand: & $($mutability)* Operand<'tcx>, + location: Location) { match *operand { Operand::Consume(ref $($mutability)* lvalue) => { - self.visit_lvalue(lvalue, LvalueContext::Consume); + self.visit_lvalue(lvalue, LvalueContext::Consume, location); } Operand::Constant(ref $($mutability)* constant) => { - self.visit_constant(constant); + self.visit_constant(constant, location); } } } fn super_lvalue(&mut self, lvalue: & $($mutability)* Lvalue<'tcx>, - context: LvalueContext) { + context: LvalueContext, + location: Location) { match *lvalue { Lvalue::Var(_) | Lvalue::Temp(_) | @@ -561,28 +589,30 @@ macro_rules! make_mir_visitor { Lvalue::ReturnPointer => { } Lvalue::Static(ref $($mutability)* def_id) => { - self.visit_def_id(def_id); + self.visit_def_id(def_id, location); } Lvalue::Projection(ref $($mutability)* proj) => { - self.visit_projection(proj, context); + self.visit_projection(proj, context, location); } } } fn super_projection(&mut self, proj: & $($mutability)* LvalueProjection<'tcx>, - context: LvalueContext) { + context: LvalueContext, + location: Location) { let Projection { ref $($mutability)* base, ref $($mutability)* elem, } = *proj; - self.visit_lvalue(base, LvalueContext::Projection); - self.visit_projection_elem(elem, context); + self.visit_lvalue(base, LvalueContext::Projection, location); + self.visit_projection_elem(elem, context, location); } fn super_projection_elem(&mut self, proj: & $($mutability)* LvalueElem<'tcx>, - _context: LvalueContext) { + _context: LvalueContext, + location: Location) { match *proj { ProjectionElem::Deref => { } @@ -592,7 +622,7 @@ macro_rules! make_mir_visitor { self.visit_ty(ty); } ProjectionElem::Index(ref $($mutability)* operand) => { - self.visit_operand(operand); + self.visit_operand(operand, location); } ProjectionElem::ConstantIndex { offset: _, min_length: _, @@ -646,7 +676,8 @@ macro_rules! make_mir_visitor { } fn super_constant(&mut self, - constant: & $($mutability)* Constant<'tcx>) { + constant: & $($mutability)* Constant<'tcx>, + location: Location) { let Constant { ref $($mutability)* span, ref $($mutability)* ty, @@ -655,11 +686,12 @@ macro_rules! make_mir_visitor { self.visit_span(span); self.visit_ty(ty); - self.visit_literal(literal); + self.visit_literal(literal, location); } fn super_typed_const_val(&mut self, - constant: & $($mutability)* TypedConstVal<'tcx>) { + constant: & $($mutability)* TypedConstVal<'tcx>, + location: Location) { let TypedConstVal { ref $($mutability)* span, ref $($mutability)* ty, @@ -668,19 +700,20 @@ macro_rules! make_mir_visitor { self.visit_span(span); self.visit_ty(ty); - self.visit_const_usize(value); + self.visit_const_usize(value, location); } fn super_literal(&mut self, - literal: & $($mutability)* Literal<'tcx>) { + literal: & $($mutability)* Literal<'tcx>, + location: Location) { match *literal { Literal::Item { ref $($mutability)* def_id, ref $($mutability)* substs } => { - self.visit_def_id(def_id); + self.visit_def_id(def_id, location); self.visit_substs(substs); } Literal::Value { ref $($mutability)* value } => { - self.visit_const_val(value); + self.visit_const_val(value, location); } Literal::Promoted { index: _ } => {} } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 66165ec6ff7d0..6b34c0a21988d 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -222,7 +222,24 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyArray(_, n) => format!("array of {} elements", n), ty::TySlice(_) => "slice".to_string(), ty::TyRawPtr(_) => "*-ptr".to_string(), - ty::TyRef(_, _) => "&-ptr".to_string(), + ty::TyRef(region, tymut) => { + let tymut_string = tymut.to_string(); + if tymut_string == "_" || //unknown type name, + tymut_string.len() > 10 || //name longer than saying "reference", + region.to_string() != "" //... or a complex type + { + match tymut { + ty::TypeAndMut{mutbl, ..} => { + format!("{}reference", match mutbl { + hir::Mutability::MutMutable => "mutable ", + _ => "" + }) + } + } + } else { + format!("&{}", tymut_string) + } + } ty::TyFnDef(..) => format!("fn item"), ty::TyFnPtr(_) => "fn pointer".to_string(), ty::TyTrait(ref inner) => { diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index 57b335bd5eee4..67c2ff726b121 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -9,10 +9,9 @@ // except according to those terms. use rustc::ty::TyCtxt; -use rustc::mir::repr::{self, Mir}; +use rustc::mir::repr::{self, Mir, Location}; use rustc_data_structures::indexed_vec::Idx; -use super::super::gather_moves::{Location}; use super::super::gather_moves::{MoveOutIndex, MovePathIndex}; use super::super::MoveDataParamEnv; use super::super::DropFlagState; @@ -252,7 +251,7 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { { drop_flag_effects_for_location( self.tcx, self.mir, ctxt, - Location { block: bb, index: idx }, + Location { block: bb, statement_index: idx }, |path, s| Self::update_bits(sets, path, s) ) } @@ -265,7 +264,7 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { { drop_flag_effects_for_location( self.tcx, self.mir, ctxt, - Location { block: bb, index: statements_len }, + Location { block: bb, statement_index: statements_len }, |path, s| Self::update_bits(sets, path, s) ) } @@ -314,7 +313,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { { drop_flag_effects_for_location( self.tcx, self.mir, ctxt, - Location { block: bb, index: idx }, + Location { block: bb, statement_index: idx }, |path, s| Self::update_bits(sets, path, s) ) } @@ -327,7 +326,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { { drop_flag_effects_for_location( self.tcx, self.mir, ctxt, - Location { block: bb, index: statements_len }, + Location { block: bb, statement_index: statements_len }, |path, s| Self::update_bits(sets, path, s) ) } @@ -375,7 +374,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { { drop_flag_effects_for_location( self.tcx, self.mir, ctxt, - Location { block: bb, index: idx }, + Location { block: bb, statement_index: idx }, |path, s| Self::update_bits(sets, path, s) ) } @@ -388,7 +387,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { { drop_flag_effects_for_location( self.tcx, self.mir, ctxt, - Location { block: bb, index: statements_len }, + Location { block: bb, statement_index: statements_len }, |path, s| Self::update_bits(sets, path, s) ) } @@ -431,7 +430,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { let path_map = &move_data.path_map; let rev_lookup = &move_data.rev_lookup; - let loc = Location { block: bb, index: idx }; + let loc = Location { block: bb, statement_index: idx }; debug!("stmt {:?} at loc {:?} moves out of move_indexes {:?}", stmt, loc, &loc_map[loc]); for move_index in &loc_map[loc] { @@ -471,7 +470,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { let (mir, move_data) = (self.mir, &ctxt.move_data); let term = mir[bb].terminator(); let loc_map = &move_data.loc_map; - let loc = Location { block: bb, index: statements_len }; + let loc = Location { block: bb, statement_index: statements_len }; debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}", term, loc, &loc_map[loc]); let bits_per_block = self.bits_per_block(ctxt); diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index f6e9484eda1a4..9a1522000039e 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -9,7 +9,7 @@ // except according to those terms. use indexed_set::IdxSetBuf; -use super::gather_moves::{MoveData, MovePathIndex, MovePathContent, Location}; +use super::gather_moves::{MoveData, MovePathIndex, MovePathContent}; use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use super::dataflow::{DataflowResults}; use super::{drop_flag_effects_for_location, on_all_children_bits}; @@ -146,9 +146,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { dead: self.flow_uninits.sets().on_entry_set_for(loc.block.index()) .to_owned(), }; - for stmt in 0..loc.index { + for stmt in 0..loc.statement_index { data.apply_location(self.tcx, self.mir, self.env, - Location { block: loc.block, index: stmt }); + Location { block: loc.block, statement_index: stmt }); } data } @@ -226,7 +226,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let init_data = self.initialization_data_at(Location { block: bb, - index: data.statements.len() + statement_index: data.statements.len() }); let path = self.move_data().rev_lookup.find(location); @@ -249,7 +249,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn elaborate_drops(&mut self) { for (bb, data) in self.mir.basic_blocks().iter_enumerated() { - let loc = Location { block: bb, index: data.statements.len() }; + let loc = Location { block: bb, statement_index: data.statements.len() }; let terminator = data.terminator(); let resume_block = self.patch.resume_block(); @@ -359,9 +359,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { unwind: Some(unwind) }, bb); on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { - self.set_drop_flag(Location { block: target, index: 0 }, + self.set_drop_flag(Location { block: target, statement_index: 0 }, child, DropFlagState::Present); - self.set_drop_flag(Location { block: unwind, index: 0 }, + self.set_drop_flag(Location { block: unwind, statement_index: 0 }, child, DropFlagState::Present); }); } @@ -741,7 +741,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let drop_block = self.drop_block(c); if update_drop_flag { self.set_drop_flag( - Location { block: drop_block, index: 0 }, + Location { block: drop_block, statement_index: 0 }, c.path, DropFlagState::Absent ); @@ -927,7 +927,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn drop_flags_on_init(&mut self) { - let loc = Location { block: START_BLOCK, index: 0 }; + let loc = Location { block: START_BLOCK, statement_index: 0 }; let span = self.patch.source_info_for_location(self.mir, loc).span; let false_ = self.constant_bool(span, false); for flag in self.drop_flags.values() { @@ -942,7 +942,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } = data.terminator().kind { assert!(!self.patch.is_patched(bb)); - let loc = Location { block: tgt, index: 0 }; + let loc = Location { block: tgt, statement_index: 0 }; let path = self.move_data().rev_lookup.find(lv); on_all_children_bits( self.tcx, self.mir, self.move_data(), path, @@ -953,7 +953,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn drop_flags_for_args(&mut self) { - let loc = Location { block: START_BLOCK, index: 0 }; + let loc = Location { block: START_BLOCK, statement_index: 0 }; super::drop_flag_effects_for_function_entry( self.tcx, self.mir, self.env, |path, ds| { self.set_drop_flag(loc, path, ds); @@ -993,7 +993,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } } } - let loc = Location { block: bb, index: i }; + let loc = Location { block: bb, statement_index: i }; super::drop_flag_effects_for_location( self.tcx, self.mir, self.env, loc, |path, ds| { if ds == DropFlagState::Absent || allow_initializations { @@ -1011,7 +1011,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } = data.terminator().kind { assert!(!self.patch.is_patched(bb)); - let loc = Location { block: bb, index: data.statements.len() }; + let loc = Location { block: bb, statement_index: data.statements.len() }; let path = self.move_data().rev_lookup.find(lv); on_all_children_bits( self.tcx, self.mir, self.move_data(), path, diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index e965dcc169c2d..2870df5ffaf33 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -160,8 +160,8 @@ impl Index for LocMap { type Output = [MoveOutIndex]; fn index(&self, index: Location) -> &Self::Output { assert!(index.block.index() < self.map.len()); - assert!(index.index < self.map[index.block.index()].len()); - &self.map[index.block.index()][index.index] + assert!(index.statement_index < self.map[index.block.index()].len()); + &self.map[index.block.index()][index.statement_index] } } @@ -200,21 +200,6 @@ impl fmt::Debug for MoveOut { } } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct Location { - /// block where action is located - pub block: BasicBlock, - /// index within above block; statement when < statments.len) or - /// the terminator (when = statements.len). - pub index: usize, -} - -impl fmt::Debug for Location { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}[{}]", self.block, self.index) - } -} - #[derive(Debug)] pub struct MovePathData<'tcx> { move_paths: Vec>, @@ -571,7 +556,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD }; for (i, stmt) in bb_data.statements.iter().enumerate() { - let source = Location { block: bb, index: i }; + let source = Location { block: bb, statement_index: i }; match stmt.kind { StatementKind::Assign(ref lval, ref rval) => { bb_ctxt.builder.create_move_path(lval); @@ -631,7 +616,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD TerminatorKind::Return => { let source = Location { block: bb, - index: bb_data.statements.len() }; + statement_index: bb_data.statements.len() }; if let FnOutput::FnConverging(_) = bb_ctxt.builder.mir.return_ty { debug!("gather_moves Return on_move_out_lval return {:?}", source); bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source); @@ -643,7 +628,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD TerminatorKind::If { ref cond, targets: _ } => { let source = Location { block: bb, - index: bb_data.statements.len() }; + statement_index: bb_data.statements.len() }; bb_ctxt.on_operand(SK::If, cond, source); } @@ -674,7 +659,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD TerminatorKind::Drop { ref location, target: _, unwind: _ } => { let source = Location { block: bb, - index: bb_data.statements.len() }; + statement_index: bb_data.statements.len() }; bb_ctxt.on_move_out_lval(SK::Drop, location, source); } TerminatorKind::DropAndReplace { ref location, ref value, .. } => { @@ -682,12 +667,12 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD bb_ctxt.path_map.fill_to(assigned_path.index()); let source = Location { block: bb, - index: bb_data.statements.len() }; + statement_index: bb_data.statements.len() }; bb_ctxt.on_operand(SK::Use, value, source); } TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => { let source = Location { block: bb, - index: bb_data.statements.len() }; + statement_index: bb_data.statements.len() }; bb_ctxt.on_operand(SK::CallFn, func, source); for arg in args { debug!("gather_moves Call on_operand {:?} {:?}", arg, source); @@ -762,7 +747,7 @@ impl<'b, 'a: 'b, 'tcx: 'a> BlockContext<'b, 'a, 'tcx> { stmt_kind: StmtKind, lval: &Lvalue<'tcx>, source: Location) { - let i = source.index; + let i = source.statement_index; let index = MoveOutIndex::new(self.moves.len()); let path = self.builder.move_path_for(lval); diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index c563fdb8f44e6..b78de00761bd5 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -19,7 +19,7 @@ use rustc::hir; use rustc::hir::intravisit::{FnKind}; use rustc::mir::repr; -use rustc::mir::repr::{BasicBlock, BasicBlockData, Mir, Statement, Terminator}; +use rustc::mir::repr::{BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location}; use rustc::session::Session; use rustc::ty::{self, TyCtxt}; @@ -35,7 +35,7 @@ use self::dataflow::{DataflowOperator}; use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults}; use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use self::dataflow::{DefinitelyInitializedLvals}; -use self::gather_moves::{MoveData, MovePathIndex, Location}; +use self::gather_moves::{MoveData, MovePathIndex}; use self::gather_moves::{MovePathContent, MovePathData}; fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option> { @@ -367,7 +367,7 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( } let block = &mir[loc.block]; - match block.statements.get(loc.index) { + match block.statements.get(loc.statement_index) { Some(stmt) => match stmt.kind { repr::StatementKind::SetDiscriminant{ .. } => { span_bug!(stmt.source_info.span, "SetDiscrimant should not exist during borrowck"); diff --git a/src/librustc_borrowck/borrowck/mir/patch.rs b/src/librustc_borrowck/borrowck/mir/patch.rs index 417e719a9dcb9..52cd1a9f949bf 100644 --- a/src/librustc_borrowck/borrowck/mir/patch.rs +++ b/src/librustc_borrowck/borrowck/mir/patch.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::gather_moves::Location; use rustc::ty::Ty; use rustc::mir::repr::*; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -89,7 +88,7 @@ impl<'tcx> MirPatch<'tcx> { }; Location { block: bb, - index: offset + statement_index: offset } } @@ -149,12 +148,12 @@ impl<'tcx> MirPatch<'tcx> { } debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta); - loc.index += delta; + loc.statement_index += delta; let source_info = Self::source_info_for_index( &mir[loc.block], loc ); mir[loc.block].statements.insert( - loc.index, Statement { + loc.statement_index, Statement { source_info: source_info, kind: stmt }); @@ -163,7 +162,7 @@ impl<'tcx> MirPatch<'tcx> { } pub fn source_info_for_index(data: &BasicBlockData, loc: Location) -> SourceInfo { - match data.statements.get(loc.index) { + match data.statements.get(loc.statement_index) { Some(stmt) => stmt.source_info, None => data.terminator().source_info } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 64b614b56e12f..bfb1285d9bcb2 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -43,6 +43,7 @@ use rustc_const_math::ConstInt; use rustc::mir; use rustc::mir::visit::MutVisitor; +use rustc::mir::repr::Location; use std::cell::Cell; use std::io; @@ -857,7 +858,7 @@ pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, impl<'v, 'cdata, 'codemap> mir::visit::MutVisitor<'v> for MirDefIdAndSpanTranslator<'cdata, 'codemap> { - fn visit_def_id(&mut self, def_id: &mut DefId) { + fn visit_def_id(&mut self, def_id: &mut DefId, _: Location) { *def_id = translate_def_id(self.crate_metadata, *def_id); } diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 83f8c3b42c850..026a79b32b8f7 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -13,7 +13,7 @@ //! Routines for manipulating the control-flow graph. -use build::{CFG, Location}; +use build::CFG; use rustc::mir::repr::*; impl<'tcx> CFG<'tcx> { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 362e1e26fdf1e..7ace500f541a7 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -101,16 +101,6 @@ pub struct ScopeAuxiliary { pub postdoms: Vec, } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub struct Location { - /// the location is within this block - pub block: BasicBlock, - - /// the location is the start of the this statement; or, if `statement_index` - /// == num-statements, then the start of the terminator. - pub statement_index: usize, -} - pub type ScopeAuxiliaryVec = IndexVec; /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index 55e7408b0fd5d..9357e9879aec0 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use build::{Location, ScopeAuxiliaryVec, ScopeId}; +use build::{ScopeAuxiliaryVec, ScopeId}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::mir::repr::*; diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 818f060ed445c..32fddd293cacd 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -19,7 +19,10 @@ use rustc::mir::transform::{Pass, MirPass, MirSource}; pub struct NoLandingPads; impl<'tcx> MutVisitor<'tcx> for NoLandingPads { - fn visit_terminator(&mut self, bb: BasicBlock, terminator: &mut Terminator<'tcx>) { + fn visit_terminator(&mut self, + bb: BasicBlock, + terminator: &mut Terminator<'tcx>, + location: Location) { match terminator.kind { TerminatorKind::Goto { .. } | TerminatorKind::Resume | @@ -37,7 +40,7 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { unwind.take(); }, } - self.super_terminator(bb, terminator); + self.super_terminator(bb, terminator, location); } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index eb0d8697f15d4..2a26e03d88e06 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -28,11 +28,10 @@ use rustc::mir::traversal::ReversePostorder; use rustc::ty::{self, TyCtxt}; use syntax_pos::Span; -use build::Location; - use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use std::mem; +use std::usize; /// State of a temporary during collection and promotion. #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -77,13 +76,12 @@ pub enum Candidate { struct TempCollector { temps: IndexVec, - location: Location, span: Span } impl<'tcx> Visitor<'tcx> for TempCollector { - fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) { - self.super_lvalue(lvalue, context); + fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) { + self.super_lvalue(lvalue, context, location); if let Lvalue::Temp(index) = *lvalue { // Ignore drops, if the temp gets promoted, // then it's constant and thus drop is noop. @@ -97,7 +95,7 @@ impl<'tcx> Visitor<'tcx> for TempCollector { LvalueContext::Store | LvalueContext::Call => { *temp = TempState::Defined { - location: self.location, + location: location, uses: 0 }; return; @@ -122,27 +120,11 @@ impl<'tcx> Visitor<'tcx> for TempCollector { fn visit_source_info(&mut self, source_info: &SourceInfo) { self.span = source_info.span; } - - fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) { - assert_eq!(self.location.block, bb); - self.super_statement(bb, statement); - self.location.statement_index += 1; - } - - fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) { - self.location.statement_index = 0; - self.location.block = bb; - self.super_basic_block_data(bb, data); - } } pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec { let mut collector = TempCollector { temps: IndexVec::from_elem(TempState::Undefined, &mir.temp_decls), - location: Location { - block: START_BLOCK, - statement_index: 0 - }, span: mir.span }; for (bb, data) in rpo { @@ -262,9 +244,15 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { // Then, recurse for components in the Rvalue or Call. if stmt_idx < no_stmts { - self.visit_rvalue(rvalue.as_mut().unwrap()); + self.visit_rvalue(rvalue.as_mut().unwrap(), Location { + block: bb, + statement_index: stmt_idx + }); } else { - self.visit_terminator_kind(bb, call.as_mut().unwrap()); + self.visit_terminator_kind(bb, call.as_mut().unwrap(), Location { + block: bb, + statement_index: no_stmts + }); } let new_temp = self.promoted.temp_decls.push(TempDecl { @@ -327,7 +315,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { } } }; - self.visit_rvalue(&mut rvalue); + self.visit_rvalue(&mut rvalue, Location{ + block: BasicBlock::new(0), + statement_index: usize::MAX + }); self.assign(Lvalue::ReturnPointer, rvalue, span); self.source.promoted.push(self.promoted); } @@ -335,11 +326,14 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { /// Replaces all temporaries with their promoted counterparts. impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { - fn visit_lvalue(&mut self, lvalue: &mut Lvalue<'tcx>, context: LvalueContext) { + fn visit_lvalue(&mut self, + lvalue: &mut Lvalue<'tcx>, + context: LvalueContext, + location: Location) { if let Lvalue::Temp(ref mut temp) = *lvalue { *temp = self.promote_temp(*temp); } - self.super_lvalue(lvalue, context); + self.super_lvalue(lvalue, context, location); } } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 7ebc72bcc5fca..f986b73202c75 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -37,8 +37,6 @@ use syntax_pos::Span; use std::collections::hash_map::Entry; use std::fmt; -use build::Location; - use super::promote_consts::{self, Candidate, TempState}; bitflags! { @@ -147,7 +145,6 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { return_qualif: Option, qualif: Qualif, const_fn_arg_vars: BitVector, - location: Location, temp_promotion_state: IndexVec, promotion_candidates: Vec } @@ -178,10 +175,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { return_qualif: None, qualif: Qualif::empty(), const_fn_arg_vars: BitVector::new(mir.var_decls.len()), - location: Location { - block: START_BLOCK, - statement_index: 0 - }, temp_promotion_state: temps, promotion_candidates: vec![] } @@ -290,7 +283,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { } /// Assign the current qualification to the given destination. - fn assign(&mut self, dest: &Lvalue<'tcx>) { + fn assign(&mut self, dest: &Lvalue<'tcx>, location: Location) { let qualif = self.qualif; let span = self.span; let store = |slot: &mut Option| { @@ -328,7 +321,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { // This must be an explicit assignment. _ => { // Catch more errors in the destination. - self.visit_lvalue(dest, LvalueContext::Store); + self.visit_lvalue(dest, LvalueContext::Store, location); self.statement_like(); } } @@ -396,7 +389,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { self.qualif = Qualif::NOT_CONST; for index in 0..mir.var_decls.len() { if !self.const_fn_arg_vars.contains(index) { - self.assign(&Lvalue::Var(Var::new(index))); + self.assign(&Lvalue::Var(Var::new(index)), Location { + block: BasicBlock::new(0), + statement_index: 0 + }); } } @@ -442,7 +438,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { /// For functions (constant or not), it also records /// candidates for promotion in promotion_candidates. impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { - fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) { + fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) { match *lvalue { Lvalue::Arg(_) => { self.add(Qualif::FN_ARGUMENT); @@ -474,7 +470,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } Lvalue::Projection(ref proj) => { self.nest(|this| { - this.super_lvalue(lvalue, context); + this.super_lvalue(lvalue, context, location); match proj.elem { ProjectionElem::Deref => { if !this.try_consume() { @@ -520,11 +516,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - fn visit_operand(&mut self, operand: &Operand<'tcx>) { + fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { match *operand { Operand::Consume(_) => { self.nest(|this| { - this.super_operand(operand); + this.super_operand(operand, location); this.try_consume(); }); } @@ -563,9 +559,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { // Recurse through operands and lvalues. - self.super_rvalue(rvalue); + self.super_rvalue(rvalue, location); match *rvalue { Rvalue::Use(_) | @@ -641,7 +637,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } // We might have a candidate for promotion. - let candidate = Candidate::Ref(self.location); + let candidate = Candidate::Ref(location); if self.mode == Mode::Fn || self.mode == Mode::ConstFn { if !self.qualif.intersects(Qualif::NEVER_PROMOTE) { // We can only promote direct borrows of temps. @@ -721,9 +717,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - fn visit_terminator_kind(&mut self, bb: BasicBlock, kind: &TerminatorKind<'tcx>) { + fn visit_terminator_kind(&mut self, + bb: BasicBlock, + kind: &TerminatorKind<'tcx>, + location: Location) { if let TerminatorKind::Call { ref func, ref args, ref destination, .. } = *kind { - self.visit_operand(func); + self.visit_operand(func, location); let fn_ty = func.ty(self.mir, self.tcx); let (is_shuffle, is_const_fn) = match fn_ty.sty { @@ -737,7 +736,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { for (i, arg) in args.iter().enumerate() { self.nest(|this| { - this.visit_operand(arg); + this.visit_operand(arg, location); if is_shuffle && i == 2 && this.mode == Mode::Fn { let candidate = Candidate::ShuffleIndices(bb); if !this.qualif.intersects(Qualif::NEVER_PROMOTE) { @@ -815,16 +814,20 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.deny_drop(); } } - self.assign(dest); + self.assign(dest, location); } } else { // Qualify any operands inside other terminators. - self.super_terminator_kind(bb, kind); + self.super_terminator_kind(bb, kind, location); } } - fn visit_assign(&mut self, _: BasicBlock, dest: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) { - self.visit_rvalue(rvalue); + fn visit_assign(&mut self, + _: BasicBlock, + dest: &Lvalue<'tcx>, + rvalue: &Rvalue<'tcx>, + location: Location) { + self.visit_rvalue(rvalue, location); // Check the allowed const fn argument forms. if let (Mode::ConstFn, &Lvalue::Var(index)) = (self.mode, dest) { @@ -845,28 +848,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - self.assign(dest); + self.assign(dest, location); } fn visit_source_info(&mut self, source_info: &SourceInfo) { self.span = source_info.span; } - fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) { - assert_eq!(self.location.block, bb); - self.nest(|this| this.super_statement(bb, statement)); - self.location.statement_index += 1; - } - - fn visit_terminator(&mut self, bb: BasicBlock, terminator: &Terminator<'tcx>) { - assert_eq!(self.location.block, bb); - self.nest(|this| this.super_terminator(bb, terminator)); + fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>, location: Location) { + self.nest(|this| this.super_statement(bb, statement, location)); } - fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) { - self.location.statement_index = 0; - self.location.block = bb; - self.super_basic_block_data(bb, data); + fn visit_terminator(&mut self, + bb: BasicBlock, + terminator: &Terminator<'tcx>, + location: Location) { + self.nest(|this| this.super_terminator(bb, terminator, location)); } } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 934357c9e1da2..cbfe9b69024c1 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -68,17 +68,20 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } - fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, _context: visit::LvalueContext) { - self.sanitize_lvalue(lvalue); + fn visit_lvalue(&mut self, + lvalue: &Lvalue<'tcx>, + _context: visit::LvalueContext, + location: Location) { + self.sanitize_lvalue(lvalue, location); } - fn visit_constant(&mut self, constant: &Constant<'tcx>) { - self.super_constant(constant); + fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { + self.super_constant(constant, location); self.sanitize_type(constant, constant.ty); } - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { - self.super_rvalue(rvalue); + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); if let Some(ty) = rvalue.ty(self.mir, self.tcx()) { self.sanitize_type(rvalue, ty); } @@ -126,7 +129,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } - fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>) -> LvalueTy<'tcx> { + fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> { debug!("sanitize_lvalue: {:?}", lvalue); match *lvalue { Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index].ty }, @@ -145,14 +148,14 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } Lvalue::Projection(ref proj) => { - let base_ty = self.sanitize_lvalue(&proj.base); + let base_ty = self.sanitize_lvalue(&proj.base, location); if let LvalueTy::Ty { ty } = base_ty { if ty.references_error() { assert!(self.errors_reported); return LvalueTy::Ty { ty: self.tcx().types.err }; } } - self.sanitize_projection(base_ty, &proj.elem, lvalue) + self.sanitize_projection(base_ty, &proj.elem, lvalue, location) } } } @@ -160,7 +163,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { fn sanitize_projection(&mut self, base: LvalueTy<'tcx>, pi: &LvalueElem<'tcx>, - lvalue: &Lvalue<'tcx>) + lvalue: &Lvalue<'tcx>, + location: Location) -> LvalueTy<'tcx> { debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue); let tcx = self.tcx(); @@ -177,7 +181,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } ProjectionElem::Index(ref i) => { - self.visit_operand(i); + self.visit_operand(i, location); let index_ty = i.ty(self.mir, tcx); if index_ty != tcx.types.usize { LvalueTy::Ty { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 4a6dbb2bdae56..ce4ac62cdace3 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -201,6 +201,7 @@ use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::mir::repr as mir; use rustc::mir::visit as mir_visit; use rustc::mir::visit::Visitor as MirVisitor; +use rustc::mir::repr::Location; use syntax::abi::Abi; use errors; @@ -445,7 +446,7 @@ struct MirNeighborCollector<'a, 'tcx: 'a> { impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>) { + fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { debug!("visiting rvalue {:?}", *rvalue); match *rvalue { @@ -516,12 +517,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { _ => { /* not interesting */ } } - self.super_rvalue(rvalue); + self.super_rvalue(rvalue, location); } fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, - context: mir_visit::LvalueContext) { + context: mir_visit::LvalueContext, + location: Location) { debug!("visiting lvalue {:?}", *lvalue); if let mir_visit::LvalueContext::Drop = context { @@ -536,10 +538,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); } - self.super_lvalue(lvalue, context); + self.super_lvalue(lvalue, context, location); } - fn visit_operand(&mut self, operand: &mir::Operand<'tcx>) { + fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { debug!("visiting operand {:?}", *operand); let callee = match *operand { @@ -582,7 +584,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } } - self.super_operand(operand); + self.super_operand(operand, location); fn can_result_in_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) @@ -616,7 +618,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // we would not register drop-glues. fn visit_terminator_kind(&mut self, block: mir::BasicBlock, - kind: &mir::TerminatorKind<'tcx>) { + kind: &mir::TerminatorKind<'tcx>, + location: Location) { let tcx = self.scx.tcx(); match *kind { mir::TerminatorKind::Call { @@ -644,7 +647,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { _ => { /* Nothing to do. */ } } - self.super_terminator_kind(block, kind); + self.super_terminator_kind(block, kind, location); fn is_drop_in_place_intrinsic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index d6dbefec03467..905ccc3e7f8b9 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -15,6 +15,7 @@ use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::mir::repr as mir; use rustc::mir::repr::TerminatorKind; +use rustc::mir::repr::Location; use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::traversal; use common::{self, Block, BlockAndBuilder}; @@ -97,7 +98,8 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { fn visit_assign(&mut self, block: mir::BasicBlock, lvalue: &mir::Lvalue<'tcx>, - rvalue: &mir::Rvalue<'tcx>) { + rvalue: &mir::Rvalue<'tcx>, + location: Location) { debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue); if let Some(index) = self.mir.local_index(lvalue) { @@ -106,15 +108,16 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { self.mark_as_lvalue(index); } } else { - self.visit_lvalue(lvalue, LvalueContext::Store); + self.visit_lvalue(lvalue, LvalueContext::Store, location); } - self.visit_rvalue(rvalue); + self.visit_rvalue(rvalue, location); } fn visit_terminator_kind(&mut self, block: mir::BasicBlock, - kind: &mir::TerminatorKind<'tcx>) { + kind: &mir::TerminatorKind<'tcx>, + location: Location) { match *kind { mir::TerminatorKind::Call { func: mir::Operand::Constant(mir::Constant { @@ -126,18 +129,19 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { // is not guaranteed to be statically dominated by the // definition of x, so x must always be in an alloca. if let mir::Operand::Consume(ref lvalue) = args[0] { - self.visit_lvalue(lvalue, LvalueContext::Drop); + self.visit_lvalue(lvalue, LvalueContext::Drop, location); } } _ => {} } - self.super_terminator_kind(block, kind); + self.super_terminator_kind(block, kind, location); } fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, - context: LvalueContext) { + context: LvalueContext, + location: Location) { debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context); // Allow uses of projections of immediate pair fields. @@ -185,11 +189,11 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { // A deref projection only reads the pointer, never needs the lvalue. if let mir::Lvalue::Projection(ref proj) = *lvalue { if let mir::ProjectionElem::Deref = proj.elem { - return self.visit_lvalue(&proj.base, LvalueContext::Consume); + return self.visit_lvalue(&proj.base, LvalueContext::Consume, location); } } - self.super_lvalue(lvalue, context); + self.super_lvalue(lvalue, context, location); } } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 8c1567939fb37..5961fd59699c1 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -25,9 +25,10 @@ use cell::RefCell; use fmt; use intrinsics; use mem; +use ptr; use raw; -use sys_common::rwlock::RWLock; use sys::stdio::Stderr; +use sys_common::rwlock::RWLock; use sys_common::thread_info; use sys_common::util; use thread; @@ -255,45 +256,76 @@ pub use realstd::rt::update_panic_count; /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. pub unsafe fn try R>(f: F) -> Result> { - let mut slot = None; - let mut f = Some(f); - let ret; - - { - let mut to_run = || { - slot = Some(f.take().unwrap()()); - }; - let fnptr = get_call(&mut to_run); - let dataptr = &mut to_run as *mut _ as *mut u8; - let mut any_data = 0; - let mut any_vtable = 0; - let fnptr = mem::transmute::(fnptr); - let r = __rust_maybe_catch_panic(fnptr, - dataptr, - &mut any_data, - &mut any_vtable); - if r == 0 { - ret = Ok(()); - } else { - update_panic_count(-1); - ret = Err(mem::transmute(raw::TraitObject { - data: any_data as *mut _, - vtable: any_vtable as *mut _, - })); - } + struct Data { + f: F, + r: R, } - debug_assert!(update_panic_count(0) == 0); - return ret.map(|()| { - slot.take().unwrap() - }); + // We do some sketchy operations with ownership here for the sake of + // performance. The `Data` structure is never actually fully valid, but + // instead it always contains at least one uninitialized field. We can only + // pass pointers down to `__rust_maybe_catch_panic` (can't pass objects by + // value), so we do all the ownership tracking here manully. + // + // Note that this is all invalid if any of these functions unwind, but the + // whole point of this function is to prevent that! As a result we go + // through a transition where: + // + // * First, only the closure we're going to call is initialized. The return + // value is uninitialized. + // * When we make the function call, the `do_call` function below, we take + // ownership of the function pointer, replacing it with uninitialized + // data. At this point the `Data` structure is entirely uninitialized, but + // it won't drop due to an unwind because it's owned on the other side of + // the catch panic. + // * If the closure successfully returns, we write the return value into the + // data's return slot. Note that `ptr::write` is used as it's overwriting + // uninitialized data. + // * Finally, when we come back out of the `__rust_maybe_catch_panic` we're + // in one of two states: + // + // 1. The closure didn't panic, in which case the return value was + // filled in. We have to be careful to `forget` the closure, + // however, as ownership was passed to the `do_call` function. + // 2. The closure panicked, in which case the return value wasn't + // filled in. In this case the entire `data` structure is invalid, + // so we forget the entire thing. + // + // Once we stack all that together we should have the "most efficient' + // method of calling a catch panic whilst juggling ownership. + let mut any_data = 0; + let mut any_vtable = 0; + let mut data = Data { + f: f, + r: mem::uninitialized(), + }; - fn get_call(_: &mut F) -> fn(&mut F) { - call - } + let r = __rust_maybe_catch_panic(do_call::, + &mut data as *mut _ as *mut u8, + &mut any_data, + &mut any_vtable); + + return if r == 0 { + let Data { f, r } = data; + mem::forget(f); + debug_assert!(update_panic_count(0) == 0); + Ok(r) + } else { + mem::forget(data); + update_panic_count(-1); + debug_assert!(update_panic_count(0) == 0); + Err(mem::transmute(raw::TraitObject { + data: any_data as *mut _, + vtable: any_vtable as *mut _, + })) + }; - fn call(f: &mut F) { - f() + fn do_call R, R>(data: *mut u8) { + unsafe { + let data = data as *mut Data; + let f = ptr::read(&mut (*data).f); + ptr::write(&mut (*data).r, f()); + } } } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index a825cf866a878..5e3ee89f5643b 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -62,12 +62,16 @@ impl<'a> StripUnconfigured<'a> { }; if attr::cfg_matches(self.config, &cfg, self.sess, self.features) { - self.process_cfg_attr(respan(mi.span, ast::Attribute_ { + let inner_attr = respan(mi.span, ast::Attribute_ { id: attr::mk_attr_id(), style: attr.node.style, value: mi.clone(), is_sugared_doc: false, - })) + }); + if attr::is_used(&attr) { + attr::mark_used(&inner_attr); + } + self.process_cfg_attr(inner_attr) } else { None } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4c279b2fe4832..e174f3ad08d6a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3788,19 +3788,18 @@ impl<'a> Parser<'a> { } /// Parse a structure field - fn parse_name_and_ty(&mut self, pr: Visibility, - attrs: Vec ) -> PResult<'a, StructField> { - let lo = match pr { - Visibility::Inherited => self.span.lo, - _ => self.last_span.lo, - }; + fn parse_name_and_ty(&mut self, + lo: BytePos, + vis: Visibility, + attrs: Vec) + -> PResult<'a, StructField> { let name = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty_sum()?; Ok(StructField { span: mk_sp(lo, self.last_span.hi), ident: Some(name), - vis: pr, + vis: vis, id: ast::DUMMY_NODE_ID, ty: ty, attrs: attrs, @@ -5120,10 +5119,11 @@ impl<'a> Parser<'a> { /// Parse a structure field declaration pub fn parse_single_struct_field(&mut self, + lo: BytePos, vis: Visibility, attrs: Vec ) -> PResult<'a, StructField> { - let a_var = self.parse_name_and_ty(vis, attrs)?; + let a_var = self.parse_name_and_ty(lo, vis, attrs)?; match self.token { token::Comma => { self.bump(); @@ -5144,8 +5144,9 @@ impl<'a> Parser<'a> { /// Parse an element of a struct definition fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = self.parse_outer_attributes()?; + let lo = self.span.lo; let vis = self.parse_visibility(true)?; - self.parse_single_struct_field(vis, attrs) + self.parse_single_struct_field(lo, vis, attrs) } // If `allow_path` is false, just parse the `pub` in `pub(path)` (but still parse `pub(crate)`) diff --git a/src/test/compile-fail/cfg_attr_path.rs b/src/test/compile-fail/cfg_attr_path.rs index 502768cc44e41..7d799850a651e 100644 --- a/src/test/compile-fail/cfg_attr_path.rs +++ b/src/test/compile-fail/cfg_attr_path.rs @@ -8,5 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[cfg_attr(all(), path = "nonexistent_file.rs")] mod foo; -//~^ ERROR nonexistent_file.rs +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![deny(unused_attributes)] // c.f #35584 + +mod auxiliary { + #[cfg_attr(any(), path = "nonexistent_file.rs")] pub mod namespaced_enums; + #[cfg_attr(all(), path = "namespaced_enums.rs")] pub mod nonexistent_file; +} + +#[rustc_error] +fn main() { //~ ERROR compilation successful + let _ = auxiliary::namespaced_enums::Foo::A; + let _ = auxiliary::nonexistent_file::Foo::A; +} diff --git a/src/test/compile-fail/coercion-slice.rs b/src/test/compile-fail/coercion-slice.rs index a619f33468f4a..6b468ff96620d 100644 --- a/src/test/compile-fail/coercion-slice.rs +++ b/src/test/compile-fail/coercion-slice.rs @@ -15,5 +15,5 @@ fn main() { //~^ ERROR mismatched types //~| expected type `&[i32]` //~| found type `[{integer}; 1]` - //~| expected &-ptr, found array of 1 elements + //~| expected &[i32], found array of 1 elements } diff --git a/src/test/compile-fail/cross-borrow-trait.rs b/src/test/compile-fail/cross-borrow-trait.rs index ea9a29c0e2ae5..672ff464718f8 100644 --- a/src/test/compile-fail/cross-borrow-trait.rs +++ b/src/test/compile-fail/cross-borrow-trait.rs @@ -21,5 +21,5 @@ pub fn main() { let _y: &Trait = x; //~ ERROR mismatched types //~| expected type `&Trait` //~| found type `Box` - //~| expected &-ptr, found box + //~| expected &Trait, found box } diff --git a/src/test/compile-fail/destructure-trait-ref.rs b/src/test/compile-fail/destructure-trait-ref.rs index d0a31fbce91ed..89fb1e105900d 100644 --- a/src/test/compile-fail/destructure-trait-ref.rs +++ b/src/test/compile-fail/destructure-trait-ref.rs @@ -42,12 +42,12 @@ fn main() { //~^ ERROR mismatched types //~| expected type `T` //~| found type `&_` - //~| expected trait T, found &-ptr + //~| expected trait T, found reference let &&&x = &(&1isize as &T); //~^ ERROR mismatched types //~| expected type `T` //~| found type `&_` - //~| expected trait T, found &-ptr + //~| expected trait T, found reference let box box x = box 1isize as Box; //~^ ERROR mismatched types //~| expected type `T` diff --git a/src/test/compile-fail/dst-bad-coercions.rs b/src/test/compile-fail/dst-bad-coercions.rs index b7a07e487994d..883c16b089581 100644 --- a/src/test/compile-fail/dst-bad-coercions.rs +++ b/src/test/compile-fail/dst-bad-coercions.rs @@ -19,12 +19,12 @@ struct Foo { } pub fn main() { - // Test that we cannot convert from *-ptr to &-ptr + // Test that we cannot convert from *-ptr to &S and &T let x: *const S = &S; let y: &S = x; //~ ERROR mismatched types let y: &T = x; //~ ERROR mismatched types - // Test that we cannot convert from *-ptr to &-ptr (mut version) + // Test that we cannot convert from *-ptr to &S and &T (mut version) let x: *mut S = &mut S; let y: &S = x; //~ ERROR mismatched types let y: &T = x; //~ ERROR mismatched types diff --git a/src/test/compile-fail/issue-12997-2.rs b/src/test/compile-fail/issue-12997-2.rs index 436d9e91dc72f..276d7f7c9ed33 100644 --- a/src/test/compile-fail/issue-12997-2.rs +++ b/src/test/compile-fail/issue-12997-2.rs @@ -17,4 +17,4 @@ fn bar(x: isize) { } //~^ ERROR mismatched types //~| expected type `fn(&mut __test::test::Bencher)` //~| found type `fn(isize) {bar}` -//~| expected &-ptr, found isize +//~| expected mutable reference, found isize diff --git a/src/test/compile-fail/issue-16338.rs b/src/test/compile-fail/issue-16338.rs index c6ce0c4c95b8b..a4517e60d66e1 100644 --- a/src/test/compile-fail/issue-16338.rs +++ b/src/test/compile-fail/issue-16338.rs @@ -18,5 +18,5 @@ fn main() { //~^ ERROR mismatched types //~| expected type `&str` //~| found type `Slice<_>` - //~| expected &-ptr, found struct `Slice` + //~| expected &str, found struct `Slice` } diff --git a/src/test/compile-fail/issue-17033.rs b/src/test/compile-fail/issue-17033.rs index 0ec05b941a960..1cd43cbb0f857 100644 --- a/src/test/compile-fail/issue-17033.rs +++ b/src/test/compile-fail/issue-17033.rs @@ -12,7 +12,7 @@ fn f<'r>(p: &'r mut fn(p: &mut ())) { (*p)(()) //~ ERROR mismatched types //~| expected type `&mut ()` //~| found type `()` - //~| expected &-ptr, found () + //~| expected &mut (), found () } fn main() {} diff --git a/src/test/compile-fail/issue-20225.rs b/src/test/compile-fail/issue-20225.rs index b7845f1f1168a..f38961c427ae9 100644 --- a/src/test/compile-fail/issue-20225.rs +++ b/src/test/compile-fail/issue-20225.rs @@ -15,13 +15,13 @@ struct Foo; impl<'a, T> Fn<(&'a T,)> for Foo { extern "rust-call" fn call(&self, (_,): (T,)) {} //~^ ERROR: has an incompatible type for trait - //~| expected &-ptr + //~| expected reference } impl<'a, T> FnMut<(&'a T,)> for Foo { extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} //~^ ERROR: has an incompatible type for trait - //~| expected &-ptr + //~| expected reference } impl<'a, T> FnOnce<(&'a T,)> for Foo { @@ -29,7 +29,7 @@ impl<'a, T> FnOnce<(&'a T,)> for Foo { extern "rust-call" fn call_once(self, (_,): (T,)) {} //~^ ERROR: has an incompatible type for trait - //~| expected &-ptr + //~| expected reference } fn main() {} diff --git a/src/test/compile-fail/issue-29084.rs b/src/test/compile-fail/issue-29084.rs index 00d2969a0f67d..6cb6bbf1893fc 100644 --- a/src/test/compile-fail/issue-29084.rs +++ b/src/test/compile-fail/issue-29084.rs @@ -13,7 +13,7 @@ macro_rules! foo { fn bar(d: u8) { } bar(&mut $d); //~^ ERROR mismatched types - //~| expected u8, found &-ptr + //~| expected u8, found &mut u8 //~| expected type `u8` //~| found type `&mut u8` }} diff --git a/src/test/compile-fail/issue-5100.rs b/src/test/compile-fail/issue-5100.rs index 9e78b7b947f98..a1f5d74b30e36 100644 --- a/src/test/compile-fail/issue-5100.rs +++ b/src/test/compile-fail/issue-5100.rs @@ -52,7 +52,7 @@ fn main() { //~^ ERROR mismatched types //~| expected type `(bool, bool)` //~| found type `&_` -//~| expected tuple, found &-ptr +//~| expected tuple, found reference } diff --git a/src/test/compile-fail/issue-5500.rs b/src/test/compile-fail/issue-5500.rs index cacbf7656def2..1cbb7588e17df 100644 --- a/src/test/compile-fail/issue-5500.rs +++ b/src/test/compile-fail/issue-5500.rs @@ -13,5 +13,5 @@ fn main() { //~^ ERROR mismatched types //~| expected type `()` //~| found type `&_` - //~| expected (), found &-ptr + //~| expected (), found reference } diff --git a/src/test/compile-fail/issue-7061.rs b/src/test/compile-fail/issue-7061.rs index 1519d71dd3be2..da6f49f3efe91 100644 --- a/src/test/compile-fail/issue-7061.rs +++ b/src/test/compile-fail/issue-7061.rs @@ -15,7 +15,7 @@ impl<'a> BarStruct { //~^ ERROR mismatched types //~| expected type `Box` //~| found type `&'a mut BarStruct` - //~| expected box, found &-ptr + //~| expected box, found mutable reference } fn main() {} diff --git a/src/test/compile-fail/issue-7867.rs b/src/test/compile-fail/issue-7867.rs index ed465117344d4..7d9f8e9058521 100644 --- a/src/test/compile-fail/issue-7867.rs +++ b/src/test/compile-fail/issue-7867.rs @@ -27,11 +27,11 @@ fn main() { //~^ ERROR mismatched types //~| expected type `&std::option::Option<{integer}>` //~| found type `std::option::Option<_>` - //~| expected &-ptr, found enum `std::option::Option` + //~| expected reference, found enum `std::option::Option` None => () //~^ ERROR mismatched types //~| expected type `&std::option::Option<{integer}>` //~| found type `std::option::Option<_>` - //~| expected &-ptr, found enum `std::option::Option` + //~| expected reference, found enum `std::option::Option` } } diff --git a/src/test/compile-fail/method-self-arg-1.rs b/src/test/compile-fail/method-self-arg-1.rs index 03816362d46c3..4c8800878f07d 100644 --- a/src/test/compile-fail/method-self-arg-1.rs +++ b/src/test/compile-fail/method-self-arg-1.rs @@ -21,7 +21,7 @@ fn main() { Foo::bar(x); //~ ERROR mismatched types //~| expected type `&Foo` //~| found type `Foo` - //~| expected &-ptr, found struct `Foo` + //~| expected &Foo, found struct `Foo` Foo::bar(&42); //~ ERROR mismatched types //~| expected type `&Foo` //~| found type `&{integer}` diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs index 5865d93e1282f..1825ec61f1ed7 100644 --- a/src/test/compile-fail/overloaded-calls-bad.rs +++ b/src/test/compile-fail/overloaded-calls-bad.rs @@ -36,7 +36,7 @@ fn main() { y: 3, }; let ans = s("what"); //~ ERROR mismatched types - //~^ NOTE expected isize, found &-ptr + //~^ NOTE expected isize, found reference //~| NOTE expected type //~| NOTE found type let ans = s(); diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index 555dd0f0c3945..5d5113ce07c71 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -38,7 +38,7 @@ fn main() { //~^ ERROR mismatched types //~| expected type `usize` //~| found type `&'static str` - //~| expected usize, found &-ptr + //~| expected usize, found reference //~| ERROR expected `usize` for repeat count, found string literal [E0306] //~| expected `usize` let f = [0; -4_isize]; diff --git a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs index 604933d40a12c..f7b046b30cad7 100644 --- a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs +++ b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs @@ -19,7 +19,7 @@ extern crate rustc_const_math; extern crate syntax; use rustc::mir::transform::{self, MirPass, MirSource}; -use rustc::mir::repr::{Mir, Literal}; +use rustc::mir::repr::{Mir, Literal, Location}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; use rustc::middle::const_val::ConstVal; @@ -40,7 +40,7 @@ impl<'tcx> MirPass<'tcx> for Pass { struct Visitor; impl<'tcx> MutVisitor<'tcx> for Visitor { - fn visit_literal(&mut self, literal: &mut Literal<'tcx>) { + fn visit_literal(&mut self, literal: &mut Literal<'tcx>, _: Location) { if let Literal::Value { ref mut value } = *literal { if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value { *i = 42; diff --git a/src/test/run-pass/issue-22894.rs b/src/test/run-pass/issue-22894.rs new file mode 100644 index 0000000000000..8acd88deef2d0 --- /dev/null +++ b/src/test/run-pass/issue-22894.rs @@ -0,0 +1,13 @@ +// Copyright 2016 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(dead_code)] +static X: &'static str = &*""; +fn main() {} diff --git a/src/test/compile-fail/pub-struct-field-span-26083.rs b/src/test/ui/span/pub-struct-field.rs similarity index 52% rename from src/test/compile-fail/pub-struct-field-span-26083.rs rename to src/test/ui/span/pub-struct-field.rs index 0dc7e09f0e4db..9f8f871200ca5 100644 --- a/src/test/compile-fail/pub-struct-field-span-26083.rs +++ b/src/test/ui/span/pub-struct-field.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,23 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Regression test for issue #26083 -// Test that span for public struct fields start at `pub` instead of the identifier +// Regression test for issue #26083 and #35435 +// Test that span for public struct fields start at `pub` -struct Foo { - pub bar: u8, +#![feature(pub_restricted)] - pub - //~^ error: field `bar` is already declared [E0124] +struct Foo { bar: u8, - - pub bar: - //~^ error: field `bar` is already declared [E0124] - u8, - - bar: - //~^ error: field `bar` is already declared [E0124] - u8, + pub bar: u8, + pub(crate) bar: u8, } -fn main() { } +fn main() {} diff --git a/src/test/ui/span/pub-struct-field.stderr b/src/test/ui/span/pub-struct-field.stderr new file mode 100644 index 0000000000000..2c002c34736c5 --- /dev/null +++ b/src/test/ui/span/pub-struct-field.stderr @@ -0,0 +1,19 @@ +error[E0124]: field `bar` is already declared + --> $DIR/pub-struct-field.rs:18:5 + | +17 | bar: u8, + | ------- `bar` first declared here +18 | pub bar: u8, + | ^^^^^^^^^^^ field already declared + +error[E0124]: field `bar` is already declared + --> $DIR/pub-struct-field.rs:19:5 + | +17 | bar: u8, + | ------- `bar` first declared here +18 | pub bar: u8, +19 | pub(crate) bar: u8, + | ^^^^^^^^^^^^^^^^^^ field already declared + +error: aborting due to 2 previous errors + diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ae8e82e4e2f60..e9ccc029bc3cf 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -137,10 +137,6 @@ impl<'test> TestCx<'test> { self.check_correct_failure_status(&proc_res); - if proc_res.status.success() { - self.fatal("process did not return an error status"); - } - let output_to_check = self.get_output(&proc_res); let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); if !expected_errors.is_empty() { diff --git a/src/tools/linkchecker/Cargo.lock b/src/tools/linkchecker/Cargo.lock index 8e94137d2139b..ed5fe081ffb2e 100644 --- a/src/tools/linkchecker/Cargo.lock +++ b/src/tools/linkchecker/Cargo.lock @@ -2,30 +2,22 @@ name = "linkchecker" version = "0.1.0" dependencies = [ - "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "libc" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "matches" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand" -version = "0.3.14" +name = "idna" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rustc-serialize" -version = "0.3.18" +name = "matches" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -43,22 +35,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "url" -version = "0.5.5" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "uuid" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml index 29fc78a65e916..415b6f0567288 100644 --- a/src/tools/linkchecker/Cargo.toml +++ b/src/tools/linkchecker/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Alex Crichton "] [dependencies] -url = "0.5" +url = "1.2" [[bin]] name = "linkchecker" diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 80c37d5597592..27adabbc72e58 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -33,7 +33,7 @@ use std::path::{Path, PathBuf}; use std::collections::{HashMap, HashSet}; use std::collections::hash_map::Entry; -use url::{Url, UrlParser}; +use url::Url; use Redirect::*; @@ -92,7 +92,7 @@ fn walk(cache: &mut Cache, root: &Path, dir: &Path, url: &mut Url, errors: &mut for entry in t!(dir.read_dir()).map(|e| t!(e)) { let path = entry.path(); let kind = t!(entry.file_type()); - url.path_mut().unwrap().push(entry.file_name().into_string().unwrap()); + url.path_segments_mut().unwrap().push(entry.file_name().to_str().unwrap()); if kind.is_dir() { walk(cache, root, &path, url, errors); } else { @@ -104,7 +104,7 @@ fn walk(cache: &mut Cache, root: &Path, dir: &Path, url: &mut Url, errors: &mut entry.source = String::new(); } } - url.path_mut().unwrap().pop(); + url.path_segments_mut().unwrap().pop(); } } @@ -138,9 +138,6 @@ fn check(cache: &mut Cache, return None; } - let mut parser = UrlParser::new(); - parser.base_url(base); - let res = load_file(cache, root, PathBuf::from(file), SkipRedirect); let (pretty_file, contents) = match res { Ok(res) => res, @@ -162,7 +159,7 @@ fn check(cache: &mut Cache, } // Once we've plucked out the URL, parse it using our base url and // then try to extract a file path. - let (parsed_url, path) = match url_to_file_path(&parser, url) { + let (parsed_url, path) = match url_to_file_path(&base, url) { Some((url, path)) => (url, PathBuf::from(path)), None => { *errors = true; @@ -203,7 +200,7 @@ fn check(cache: &mut Cache, Err(LoadError::IsRedirect) => unreachable!(), }; - if let Some(ref fragment) = parsed_url.fragment { + if let Some(ref fragment) = parsed_url.fragment() { // Fragments like `#1-6` are most likely line numbers to be // interpreted by javascript, so we're ignoring these if fragment.splitn(2, '-') @@ -214,7 +211,7 @@ fn check(cache: &mut Cache, let entry = &mut cache.get_mut(&pretty_path).unwrap(); entry.parse_ids(&pretty_path, &contents, errors); - if !entry.ids.contains(fragment) { + if !entry.ids.contains(*fragment) { *errors = true; print!("{}:{}: broken link fragment ", pretty_file.display(), @@ -271,10 +268,8 @@ fn load_file(cache: &mut Cache, } }; let base = Url::from_file_path(&file).unwrap(); - let mut parser = UrlParser::new(); - parser.base_url(&base); - match maybe_redirect.and_then(|url| url_to_file_path(&parser, &url)) { + match maybe_redirect.and_then(|url| url_to_file_path(&base, &url)) { Some((_, redirect_file)) => { let path = PathBuf::from(redirect_file); load_file(cache, root, path, FromRedirect(true)) @@ -299,8 +294,8 @@ fn maybe_redirect(source: &str) -> Option { }) } -fn url_to_file_path(parser: &UrlParser, url: &str) -> Option<(Url, PathBuf)> { - parser.parse(url) +fn url_to_file_path(parser: &Url, url: &str) -> Option<(Url, PathBuf)> { + parser.join(url) .ok() .and_then(|parsed_url| parsed_url.to_file_path().ok().map(|f| (parsed_url, f))) }