diff --git a/mk/crates.mk b/mk/crates.mk index 1583515014a39..2b168b8f0e448 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -109,7 +109,7 @@ DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml \ log graphviz rustc_llvm rustc_back rustc_data_structures\ rustc_const_math DEPS_rustc_back := std syntax flate log libc -DEPS_rustc_borrowck := rustc rustc_mir log graphviz syntax +DEPS_rustc_borrowck := rustc log graphviz syntax rustc_mir DEPS_rustc_data_structures := std log serialize DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \ rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \ @@ -123,9 +123,9 @@ DEPS_rustc_passes := syntax rustc core rustc_const_eval DEPS_rustc_mir := rustc syntax rustc_const_math rustc_const_eval rustc_bitflags DEPS_rustc_resolve := arena rustc log syntax DEPS_rustc_platform_intrinsics := std -DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir +DEPS_rustc_plugin := rustc rustc_metadata syntax DEPS_rustc_privacy := rustc log syntax -DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \ +DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \ log syntax serialize rustc_llvm rustc_platform_intrinsics \ rustc_const_math rustc_const_eval rustc_incremental DEPS_rustc_incremental := rbml rustc serialize rustc_data_structures diff --git a/src/doc/book/slice-patterns.md b/src/doc/book/slice-patterns.md index de165b70fc402..fcedf0c994f9c 100644 --- a/src/doc/book/slice-patterns.md +++ b/src/doc/book/slice-patterns.md @@ -10,7 +10,7 @@ fn main() { let v = vec!["match_this", "1"]; match &v[..] { - ["match_this", second] => println!("The second element is {}", second), + &["match_this", second] => println!("The second element is {}", second), _ => {}, } } @@ -26,8 +26,8 @@ slice will be bound to that name. For example: fn is_symmetric(list: &[u32]) -> bool { match list { - [] | [_] => true, - [x, inside.., y] if x == y => is_symmetric(inside), + &[] | &[_] => true, + &[x, ref inside.., y] if x == y => is_symmetric(inside), _ => false } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index e1fb701e641bf..301c6e3dd1c4a 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -106,6 +106,7 @@ pub mod mir { pub mod tcx; pub mod visit; pub mod transform; + pub mod traversal; pub mod mir_map; } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 48b5420dd6be7..ba93e89767716 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -993,40 +993,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } } } - PatKind::Vec(_, Some(ref slice_pat), _) => { - // The `slice_pat` here creates a slice into - // the original vector. This is effectively a - // borrow of the elements of the vector being - // matched. - - let (slice_cmt, slice_mutbl, slice_r) = - return_if_err!(mc.cat_slice_pattern(cmt_pat, &slice_pat)); - - // Note: We declare here that the borrow - // occurs upon entering the `[...]` - // pattern. This implies that something like - // `[a; b]` where `a` is a move is illegal, - // because the borrow is already in effect. - // In fact such a move would be safe-ish, but - // it effectively *requires* that we use the - // nulling out semantics to indicate when a - // value has been moved, which we are trying - // to move away from. Otherwise, how can we - // indicate that the first element in the - // vector has been moved? Eventually, we - // could perhaps modify this rule to permit - // `[..a, b]` where `b` is a move, because in - // that case we can adjust the length of the - // original vec accordingly, but we'd have to - // make trans do the right thing, and it would - // only work for `Box<[T]>`s. It seems simpler - // to just require that people call - // `vec.pop()` or `vec.unshift()`. - let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl); - delegate.borrow(pat.id, pat.span, - slice_cmt, slice_r, - slice_bk, RefBinding); - } _ => {} } })); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 31e3db51f55d8..1ea3a469d9c95 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -228,10 +228,10 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult { Ok(deref_interior(InteriorField(PositionalField(0)))) } - ty::TyArray(_, _) | ty::TySlice(_) | ty::TyStr => { + ty::TyArray(_, _) | ty::TySlice(_) => { // no deref of indexed content without supplying InteriorOffsetKind if let Some(context) = context { - Ok(deref_interior(InteriorElement(context, element_kind(t)))) + Ok(deref_interior(InteriorElement(context, ElementKind::VecElement))) } else { Err(()) } @@ -981,18 +981,19 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let method_call = ty::MethodCall::expr(elt.id()); let method_ty = self.infcx.node_method_ty(method_call); - let element_ty = match method_ty { + let (element_ty, element_kind) = match method_ty { Some(method_ty) => { let ref_ty = self.overloaded_method_return_ty(method_ty); base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty); // FIXME(#20649) -- why are we using the `self_ty` as the element type...? let self_ty = method_ty.fn_sig().input(0); - self.tcx().no_late_bound_regions(&self_ty).unwrap() + (self.tcx().no_late_bound_regions(&self_ty).unwrap(), + ElementKind::OtherElement) } None => { match base_cmt.ty.builtin_index() { - Some(ty) => ty, + Some(ty) => (ty, ElementKind::VecElement), None => { return Err(()); } @@ -1000,102 +1001,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } }; - let m = base_cmt.mutbl.inherit(); - let ret = interior(elt, base_cmt.clone(), base_cmt.ty, - m, context, element_ty); + let interior_elem = InteriorElement(context, element_kind); + let ret = + self.cat_imm_interior(elt, base_cmt.clone(), element_ty, interior_elem); debug!("cat_index ret {:?}", ret); return Ok(ret); - - fn interior<'tcx, N: ast_node>(elt: &N, - of_cmt: cmt<'tcx>, - vec_ty: Ty<'tcx>, - mutbl: MutabilityCategory, - context: InteriorOffsetKind, - element_ty: Ty<'tcx>) -> cmt<'tcx> - { - let interior_elem = InteriorElement(context, element_kind(vec_ty)); - Rc::new(cmt_ { - id:elt.id(), - span:elt.span(), - cat:Categorization::Interior(of_cmt, interior_elem), - mutbl:mutbl, - ty:element_ty, - note: NoteNone - }) - } - } - - // Takes either a vec or a reference to a vec and returns the cmt for the - // underlying vec. - fn deref_vec(&self, - elt: &N, - base_cmt: cmt<'tcx>, - context: InteriorOffsetKind) - -> McResult> - { - let ret = match deref_kind(base_cmt.ty, Some(context))? { - deref_ptr(ptr) => { - // for unique ptrs, we inherit mutability from the - // owning reference. - let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr); - - // the deref is explicit in the resulting cmt - Rc::new(cmt_ { - id:elt.id(), - span:elt.span(), - cat:Categorization::Deref(base_cmt.clone(), 0, ptr), - mutbl:m, - ty: match base_cmt.ty.builtin_deref(false, ty::NoPreference) { - Some(mt) => mt.ty, - None => bug!("Found non-derefable type") - }, - note: NoteNone - }) - } - - deref_interior(_) => { - base_cmt - } - }; - debug!("deref_vec ret {:?}", ret); - Ok(ret) - } - - /// Given a pattern P like: `[_, ..Q, _]`, where `vec_cmt` is the cmt for `P`, `slice_pat` is - /// the pattern `Q`, returns: - /// - /// * a cmt for `Q` - /// * the mutability and region of the slice `Q` - /// - /// These last two bits of info happen to be things that borrowck needs. - pub fn cat_slice_pattern(&self, - vec_cmt: cmt<'tcx>, - slice_pat: &hir::Pat) - -> McResult<(cmt<'tcx>, hir::Mutability, ty::Region)> { - let slice_ty = self.node_ty(slice_pat.id)?; - let (slice_mutbl, slice_r) = vec_slice_info(slice_pat, slice_ty); - let context = InteriorOffsetKind::Pattern; - let cmt_vec = self.deref_vec(slice_pat, vec_cmt, context)?; - let cmt_slice = self.cat_index(slice_pat, cmt_vec, context)?; - return Ok((cmt_slice, slice_mutbl, slice_r)); - - /// In a pattern like [a, b, ..c], normally `c` has slice type, but if you have [a, b, - /// ..ref c], then the type of `ref c` will be `&&[]`, so to extract the slice details we - /// have to recurse through rptrs. - fn vec_slice_info(pat: &hir::Pat, slice_ty: Ty) - -> (hir::Mutability, ty::Region) { - match slice_ty.sty { - ty::TyRef(r, ref mt) => match mt.ty.sty { - ty::TySlice(_) => (mt.mutbl, *r), - _ => vec_slice_info(pat, mt.ty), - }, - - _ => { - span_bug!(pat.span, - "type of slice pattern is not a slice"); - } - } - } } pub fn cat_imm_interior(&self, @@ -1319,15 +1229,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { PatKind::Vec(ref before, ref slice, ref after) => { let context = InteriorOffsetKind::Pattern; - let vec_cmt = self.deref_vec(pat, cmt, context)?; - let elt_cmt = self.cat_index(pat, vec_cmt, context)?; + let elt_cmt = self.cat_index(pat, cmt, context)?; for before_pat in before { self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?; } if let Some(ref slice_pat) = *slice { - let slice_ty = self.pat_ty(&slice_pat)?; - let slice_cmt = self.cat_rvalue_node(pat.id(), pat.span(), slice_ty); - self.cat_pattern_(slice_cmt, &slice_pat, op)?; + self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?; } for after_pat in after { self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?; @@ -1620,18 +1527,6 @@ impl fmt::Debug for InteriorKind { } } -fn element_kind(t: Ty) -> ElementKind { - match t.sty { - ty::TyRef(_, ty::TypeAndMut{ty, ..}) | - ty::TyBox(ty) => match ty.sty { - ty::TySlice(_) => VecElement, - _ => OtherElement - }, - ty::TyArray(..) | ty::TySlice(_) => VecElement, - _ => OtherElement - } -} - impl fmt::Debug for Upvar { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}/{:?}", self.id, self.kind) diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 9666741d032b8..7aaaf38400e87 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -32,9 +32,9 @@ pub struct Mir<'tcx> { /// that indexes into this vector. pub basic_blocks: Vec>, - /// List of lexical scopes; these are referenced by statements and - /// used (eventually) for debuginfo. Indexed by a `ScopeId`. - pub scopes: Vec, + /// List of visibility (lexical) scopes; these are referenced by statements + /// and used (eventually) for debuginfo. Indexed by a `VisibilityScope`. + pub visibility_scopes: Vec, /// Rvalues promoted from this function, such as borrows of constants. /// Each of them is the Mir of a constant with the fn's type parameters @@ -100,6 +100,18 @@ impl<'tcx> IndexMut for Mir<'tcx> { } } +/// Grouped information about the source code origin of a MIR entity. +/// Intended to be inspected by diagnostics and debuginfo. +/// Most passes can work with it as a whole, within a single function. +#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] +pub struct SourceInfo { + /// Source span for the AST pertaining to this MIR entity. + pub span: Span, + + /// The lexical visibility scope, i.e. which bindings can be seen. + pub scope: VisibilityScope +} + /////////////////////////////////////////////////////////////////////////// // Mutability and borrow kinds @@ -172,11 +184,8 @@ pub struct VarDecl<'tcx> { /// type inferred for this variable (`let x: ty = ...`) pub ty: Ty<'tcx>, - /// scope in which variable was declared - pub scope: ScopeId, - - /// span where variable was declared - pub span: Span, + /// source information (span, scope, etc.) for the declaration + pub source_info: SourceInfo, } /// A "temp" is a temporary that we place on the stack. They are @@ -275,8 +284,7 @@ pub struct BasicBlockData<'tcx> { #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct Terminator<'tcx> { - pub span: Span, - pub scope: ScopeId, + pub source_info: SourceInfo, pub kind: TerminatorKind<'tcx> } @@ -587,8 +595,7 @@ pub enum AssertMessage<'tcx> { #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Statement<'tcx> { - pub span: Span, - pub scope: ScopeId, + pub source_info: SourceInfo, pub kind: StatementKind<'tcx>, } @@ -667,6 +674,14 @@ pub enum ProjectionElem<'tcx, V> { from_end: bool, }, + /// These indices are generated by slice patterns. + /// + /// slice[from:-to] in Python terms. + Subslice { + from: u32, + to: u32, + }, + /// "Downcast" to a variant of an ADT. Currently, we only introduce /// this for ADTs with more than one variant. It may be better to /// just introduce it always, or always for enums. @@ -746,6 +761,14 @@ impl<'tcx> Debug for Lvalue<'tcx> { write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length), ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length), + ProjectionElem::Subslice { from, to } if to == 0 => + write!(fmt, "{:?}[{:?}:", data.base, from), + ProjectionElem::Subslice { from, to } if from == 0 => + write!(fmt, "{:?}[:-{:?}]", data.base, to), + ProjectionElem::Subslice { from, to } => + write!(fmt, "{:?}[{:?}:-{:?}]", data.base, + from, to), + }, } } @@ -754,29 +777,32 @@ impl<'tcx> Debug for Lvalue<'tcx> { /////////////////////////////////////////////////////////////////////////// // Scopes -impl Index for Vec { - type Output = ScopeData; +impl Index for Vec { + type Output = VisibilityScopeData; #[inline] - fn index(&self, index: ScopeId) -> &ScopeData { + fn index(&self, index: VisibilityScope) -> &VisibilityScopeData { &self[index.index()] } } -impl IndexMut for Vec { +impl IndexMut for Vec { #[inline] - fn index_mut(&mut self, index: ScopeId) -> &mut ScopeData { + fn index_mut(&mut self, index: VisibilityScope) -> &mut VisibilityScopeData { &mut self[index.index()] } } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)] -pub struct ScopeId(u32); +pub struct VisibilityScope(u32); + +/// The visibility scope all arguments go into. +pub const ARGUMENT_VISIBILITY_SCOPE: VisibilityScope = VisibilityScope(0); -impl ScopeId { - pub fn new(index: usize) -> ScopeId { +impl VisibilityScope { + pub fn new(index: usize) -> VisibilityScope { assert!(index < (u32::MAX as usize)); - ScopeId(index as u32) + VisibilityScope(index as u32) } pub fn index(self) -> usize { @@ -785,9 +811,9 @@ impl ScopeId { } #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct ScopeData { +pub struct VisibilityScopeData { pub span: Span, - pub parent_scope: Option, + pub parent_scope: Option, } /////////////////////////////////////////////////////////////////////////// @@ -846,17 +872,6 @@ pub enum Rvalue<'tcx> { /// away after type-checking and before lowering. Aggregate(AggregateKind<'tcx>, Vec>), - /// Generates a slice of the form `&input[from_start..L-from_end]` - /// where `L` is the length of the slice. This is only created by - /// slice pattern matching, so e.g. a pattern of the form `[x, y, - /// .., z]` might create a slice with `from_start=2` and - /// `from_end=1`. - Slice { - input: Lvalue<'tcx>, - from_start: usize, - from_end: usize, - }, - InlineAsm { asm: InlineAsm, outputs: Vec>, @@ -962,8 +977,6 @@ impl<'tcx> Debug for Rvalue<'tcx> { InlineAsm { ref asm, ref outputs, ref inputs } => { write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs) } - Slice { ref input, from_start, from_end } => - write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end), Ref(_, borrow_kind, ref lv) => { let kind_str = match borrow_kind { diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index d0ac98a79587a..270e33c48f1a0 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -59,6 +59,20 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { LvalueTy::Ty { ty: self.to_ty(tcx).builtin_index().unwrap() }, + ProjectionElem::Subslice { from, to } => { + let ty = self.to_ty(tcx); + LvalueTy::Ty { + ty: match ty.sty { + ty::TyArray(inner, size) => { + tcx.mk_array(inner, size-(from as usize)-(to as usize)) + } + ty::TySlice(..) => ty, + _ => { + bug!("cannot subslice non-array type: `{:?}`", self) + } + } + } + } ProjectionElem::Downcast(adt_def1, index) => match self.to_ty(tcx).sty { ty::TyEnum(adt_def, substs) => { @@ -219,7 +233,6 @@ impl<'a, 'gcx, 'tcx> Mir<'tcx> { } } } - Rvalue::Slice { .. } => None, Rvalue::InlineAsm { .. } => None } } diff --git a/src/librustc_mir/traversal.rs b/src/librustc/mir/traversal.rs similarity index 99% rename from src/librustc_mir/traversal.rs rename to src/librustc/mir/traversal.rs index c58b5c8772461..c4e4936df9541 100644 --- a/src/librustc_mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -12,7 +12,7 @@ use std::vec; use rustc_data_structures::bitvec::BitVector; -use rustc::mir::repr::*; +use super::repr::*; /// Preorder traversal of a graph. /// diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 5c9582b945bb8..22b3caf6d0c0f 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -97,9 +97,9 @@ macro_rules! make_mir_visitor { self.super_basic_block_data(block, data); } - fn visit_scope_data(&mut self, - scope_data: & $($mutability)* ScopeData) { - self.super_scope_data(scope_data); + fn visit_visibility_scope_data(&mut self, + scope_data: & $($mutability)* VisibilityScopeData) { + self.super_visibility_scope_data(scope_data); } fn visit_statement(&mut self, @@ -186,6 +186,11 @@ macro_rules! make_mir_visitor { self.super_span(span); } + fn visit_source_info(&mut self, + source_info: & $($mutability)* SourceInfo) { + self.super_source_info(source_info); + } + fn visit_fn_output(&mut self, fn_output: & $($mutability)* FnOutput<'tcx>) { self.super_fn_output(fn_output); @@ -236,9 +241,9 @@ macro_rules! make_mir_visitor { self.super_arg_decl(arg_decl); } - fn visit_scope_id(&mut self, - scope_id: & $($mutability)* ScopeId) { - self.super_scope_id(scope_id); + fn visit_visibility_scope(&mut self, + scope: & $($mutability)* VisibilityScope) { + self.super_visibility_scope(scope); } // The `super_xxx` methods comprise the default behavior and are @@ -248,7 +253,7 @@ macro_rules! make_mir_visitor { mir: & $($mutability)* Mir<'tcx>) { let Mir { ref $($mutability)* basic_blocks, - ref $($mutability)* scopes, + ref $($mutability)* visibility_scopes, promoted: _, // Visited by passes separately. ref $($mutability)* return_ty, ref $($mutability)* var_decls, @@ -263,8 +268,8 @@ macro_rules! make_mir_visitor { self.visit_basic_block_data(block, data); } - for scope in scopes { - self.visit_scope_data(scope); + for scope in visibility_scopes { + self.visit_visibility_scope_data(scope); } self.visit_fn_output(return_ty); @@ -302,16 +307,16 @@ macro_rules! make_mir_visitor { } } - fn super_scope_data(&mut self, - scope_data: & $($mutability)* ScopeData) { - let ScopeData { + fn super_visibility_scope_data(&mut self, + scope_data: & $($mutability)* VisibilityScopeData) { + let VisibilityScopeData { ref $($mutability)* span, ref $($mutability)* parent_scope, } = *scope_data; self.visit_span(span); if let Some(ref $($mutability)* parent_scope) = *parent_scope { - self.visit_scope_id(parent_scope); + self.visit_visibility_scope(parent_scope); } } @@ -319,13 +324,11 @@ macro_rules! make_mir_visitor { block: BasicBlock, statement: & $($mutability)* Statement<'tcx>) { let Statement { - ref $($mutability)* span, - ref $($mutability)* scope, + ref $($mutability)* source_info, ref $($mutability)* kind, } = *statement; - self.visit_span(span); - self.visit_scope_id(scope); + self.visit_source_info(source_info); match *kind { StatementKind::Assign(ref $($mutability)* lvalue, ref $($mutability)* rvalue) => { @@ -346,13 +349,11 @@ macro_rules! make_mir_visitor { block: BasicBlock, terminator: &$($mutability)* Terminator<'tcx>) { let Terminator { - ref $($mutability)* span, - ref $($mutability)* scope, + ref $($mutability)* source_info, ref $($mutability)* kind, } = *terminator; - self.visit_span(span); - self.visit_scope_id(scope); + self.visit_source_info(source_info); self.visit_terminator_kind(block, kind); } @@ -532,15 +533,6 @@ macro_rules! make_mir_visitor { } } - Rvalue::Slice { ref $($mutability)* input, - from_start, - from_end } => { - self.visit_lvalue(input, LvalueContext::Slice { - from_start: from_start, - from_end: from_end, - }); - } - Rvalue::InlineAsm { ref $($mutability)* outputs, ref $($mutability)* inputs, asm: _ } => { @@ -601,6 +593,8 @@ macro_rules! make_mir_visitor { match *proj { ProjectionElem::Deref => { } + ProjectionElem::Subslice { from: _, to: _ } => { + } ProjectionElem::Field(_field, ref $($mutability)* ty) => { self.visit_ty(ty); } @@ -622,13 +616,11 @@ macro_rules! make_mir_visitor { mutability: _, name: _, ref $($mutability)* ty, - ref $($mutability)* scope, - ref $($mutability)* span, + ref $($mutability)* source_info, } = *var_decl; self.visit_ty(ty); - self.visit_scope_id(scope); - self.visit_span(span); + self.visit_source_info(source_info); } fn super_temp_decl(&mut self, @@ -651,8 +643,8 @@ macro_rules! make_mir_visitor { self.visit_ty(ty); } - fn super_scope_id(&mut self, - _scope_id: & $($mutability)* ScopeId) { + fn super_visibility_scope(&mut self, + _scope: & $($mutability)* VisibilityScope) { } fn super_branch(&mut self, @@ -707,6 +699,16 @@ macro_rules! make_mir_visitor { fn super_span(&mut self, _span: & $($mutability)* Span) { } + fn super_source_info(&mut self, source_info: & $($mutability)* SourceInfo) { + let SourceInfo { + ref $($mutability)* span, + ref $($mutability)* scope, + } = *source_info; + + self.visit_span(span); + self.visit_visibility_scope(scope); + } + fn super_fn_output(&mut self, fn_output: & $($mutability)* FnOutput<'tcx>) { match *fn_output { FnOutput::FnConverging(ref $($mutability)* ty) => { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 07156c67a2207..d305a772ae5db 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -17,6 +17,8 @@ use session::Session; use traits; use ty::{self, Ty, TyCtxt, TypeFoldable}; +use util::common::slice_pat; + use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; use syntax::codemap::DUMMY_SP; @@ -98,17 +100,17 @@ impl TargetDataLayout { let mut dl = TargetDataLayout::default(); for spec in sess.target.target.data_layout.split("-") { - match &spec.split(":").collect::>()[..] { - ["e"] => dl.endian = Endian::Little, - ["E"] => dl.endian = Endian::Big, - ["a", a..] => dl.aggregate_align = align(a, "a"), - ["f32", a..] => dl.f32_align = align(a, "f32"), - ["f64", a..] => dl.f64_align = align(a, "f64"), - [p @ "p", s, a..] | [p @ "p0", s, a..] => { + match slice_pat(&&spec.split(":").collect::>()[..]) { + &["e"] => dl.endian = Endian::Little, + &["E"] => dl.endian = Endian::Big, + &["a", ref a..] => dl.aggregate_align = align(a, "a"), + &["f32", ref a..] => dl.f32_align = align(a, "f32"), + &["f64", ref a..] => dl.f64_align = align(a, "f64"), + &[p @ "p", s, ref a..] | &[p @ "p0", s, ref a..] => { dl.pointer_size = size(s, p); dl.pointer_align = align(a, p); } - [s, a..] if s.starts_with("i") => { + &[s, ref a..] if s.starts_with("i") => { let ty_align = match s[1..].parse::() { Ok(1) => &mut dl.i8_align, Ok(8) => &mut dl.i8_align, @@ -123,7 +125,7 @@ impl TargetDataLayout { }; *ty_align = align(a, s); } - [s, a..] if s.starts_with("v") => { + &[s, ref a..] if s.starts_with("v") => { let v_size = size(&s[1..], "v"); let a = align(a, s); if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) { diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index bdfb97549d5d5..57c429152c899 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -247,3 +247,15 @@ pub fn path2cstr(p: &Path) -> CString { pub fn path2cstr(p: &Path) -> CString { CString::new(p.to_str().unwrap()).unwrap() } + +// FIXME(stage0): remove this +// HACK: this is needed because the interpretation of slice +// patterns changed between stage0 and now. +#[cfg(stage0)] +pub fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'a &'b [T] { + t +} +#[cfg(not(stage0))] +pub fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'b [T] { + *t +} diff --git a/src/librustc_borrowck/borrowck/mir/abs_domain.rs b/src/librustc_borrowck/borrowck/mir/abs_domain.rs index aa885eb47424d..155b615d83c7b 100644 --- a/src/librustc_borrowck/borrowck/mir/abs_domain.rs +++ b/src/librustc_borrowck/borrowck/mir/abs_domain.rs @@ -49,6 +49,8 @@ impl<'tcx> Lift for LvalueElem<'tcx> { ProjectionElem::Field(f.clone(), ty.clone()), ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()), + ProjectionElem::Subslice {from, to} => + ProjectionElem::Subslice { from: from, to: to }, ProjectionElem::ConstantIndex {offset,min_length,from_end} => ProjectionElem::ConstantIndex { offset: offset, diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 74dc921b0bba5..8c528f10b57ba 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -151,7 +151,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, terminator: &'a Option>) -> Option<(&'a [repr::Operand<'tcx>], Span)> { - if let Some(repr::Terminator { ref kind, span, .. }) = *terminator { + if let Some(repr::Terminator { ref kind, source_info, .. }) = *terminator { if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind { if let repr::Operand::Constant(ref func) = *oper @@ -161,7 +161,7 @@ fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let name = tcx.item_name(def_id); if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { if name.as_str() == "rustc_peek" { - return Some((args, span)); + return Some((args, source_info.span)); } } } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index e783420fa065c..b09db70e7b88a 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -124,8 +124,7 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> { #[derive(Copy, Clone, Debug)] struct DropCtxt<'a, 'tcx: 'a> { - span: Span, - scope: ScopeId, + source_info: SourceInfo, is_cleanup: bool, init_data: &'a InitializationData, @@ -273,8 +272,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let init_data = self.initialization_data_at(loc); let path = self.move_data().rev_lookup.find(location); self.elaborate_drop(&DropCtxt { - span: terminator.span, - scope: terminator.scope, + source_info: terminator.source_info, is_cleanup: data.is_cleanup, init_data: &init_data, lvalue: location, @@ -329,8 +327,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let assign = Statement { kind: StatementKind::Assign(location.clone(), Rvalue::Use(value.clone())), - span: terminator.span, - scope: terminator.scope + source_info: terminator.source_info }; let unwind = unwind.unwrap_or(self.patch.resume_block()); @@ -367,8 +364,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let path = self.move_data().rev_lookup.find(location); self.elaborate_drop(&DropCtxt { - span: terminator.span, - scope: terminator.scope, + source_info: terminator.source_info, is_cleanup: data.is_cleanup, init_data: &init_data, lvalue: location, @@ -513,8 +509,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { debug!("drop_ladder: for std field {} ({:?})", i, lv); self.elaborated_drop_block(&DropCtxt { - span: c.span, - scope: c.scope, + source_info: c.source_info, is_cleanup: is_cleanup, init_data: c.init_data, lvalue: lv, @@ -527,8 +522,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { debug!("drop_ladder: for rest field {} ({:?})", i, lv); let blk = self.complete_drop(&DropCtxt { - span: c.span, - scope: c.scope, + source_info: c.source_info, is_cleanup: is_cleanup, init_data: c.init_data, lvalue: lv, @@ -785,7 +779,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.patch.new_block(BasicBlockData { statements: vec![], terminator: Some(Terminator { - scope: c.scope, span: c.span, kind: k + source_info: c.source_info, kind: k }), is_cleanup: is_cleanup }) @@ -858,11 +852,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let mut statements = vec![]; if let Some(&flag) = self.drop_flags.get(&c.path) { statements.push(Statement { - span: c.span, - scope: c.scope, + source_info: c.source_info, kind: StatementKind::Assign( Lvalue::Temp(flag), - self.constant_bool(c.span, false) + self.constant_bool(c.source_info.span, false) ) }); } @@ -880,9 +873,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.patch.new_block(BasicBlockData { statements: statements, terminator: Some(Terminator { - scope: c.scope, span: c.span, kind: TerminatorKind::Call { + source_info: c.source_info, kind: TerminatorKind::Call { func: Operand::Constant(Constant { - span: c.span, + span: c.source_info.span, ty: fty, literal: Literal::Item { def_id: free_func, @@ -910,7 +903,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { ty::TyStruct(def, _) | ty::TyEnum(def, _) => { if def.has_dtor() { self.tcx.sess.span_warn( - c.span, + c.source_info.span, &format!("dataflow bug??? moving out of type with dtor {:?}", c)); true @@ -932,7 +925,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) { if let Some(&flag) = self.drop_flags.get(&path) { - let span = self.patch.context_for_location(self.mir, loc).0; + let span = self.patch.source_info_for_location(self.mir, loc).span; let val = self.constant_bool(span, val.value()); self.patch.add_assign(loc, Lvalue::Temp(flag), val); } @@ -940,7 +933,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn drop_flags_on_init(&mut self) { let loc = Location { block: START_BLOCK, index: 0 }; - let span = self.patch.context_for_location(self.mir, loc).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() { self.patch.add_assign(loc, Lvalue::Temp(*flag), false_.clone()); diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 27d208240ac1c..1acee8e64a9af 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -620,22 +620,6 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD Rvalue::Ref(..) | Rvalue::Len(..) | Rvalue::InlineAsm { .. } => {} - - Rvalue::Slice {..} => { - // A slice pattern `x..` binds `x` to a - // reference; thus no move occurs. - // - // FIXME: I recall arielb1 questioning - // whether this is even a legal thing to - // have as an R-value. The particular - // example where I am seeing this arise is - // `TargetDataLayout::parse(&Session)` in - // `rustc::ty::layout`. - // - // this should be removed soon. - debug!("encountered Rvalue::Slice as RHS of Assign, source: {:?}", - source); - } } } } diff --git a/src/librustc_borrowck/borrowck/mir/patch.rs b/src/librustc_borrowck/borrowck/mir/patch.rs index b390c19af1a5b..b838881251da3 100644 --- a/src/librustc_borrowck/borrowck/mir/patch.rs +++ b/src/librustc_borrowck/borrowck/mir/patch.rs @@ -11,7 +11,6 @@ use super::gather_moves::Location; use rustc::ty::Ty; use rustc::mir::repr::*; -use syntax::codemap::Span; use std::iter; use std::u32; @@ -62,8 +61,10 @@ impl<'tcx> MirPatch<'tcx> { result.new_block(BasicBlockData { statements: vec![], terminator: Some(Terminator { - span: mir.span, - scope: ScopeId::new(0), + source_info: SourceInfo { + span: mir.span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, kind: TerminatorKind::Resume }), is_cleanup: true @@ -154,31 +155,30 @@ impl<'tcx> MirPatch<'tcx> { debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta); loc.index += delta; - let (span, scope) = Self::context_for_index( + let source_info = Self::source_info_for_index( mir.basic_block_data(loc.block), loc ); mir.basic_block_data_mut(loc.block).statements.insert( loc.index, Statement { - span: span, - scope: scope, + source_info: source_info, kind: stmt }); delta += 1; } } - pub fn context_for_index(data: &BasicBlockData, loc: Location) -> (Span, ScopeId) { + pub fn source_info_for_index(data: &BasicBlockData, loc: Location) -> SourceInfo { match data.statements.get(loc.index) { - Some(stmt) => (stmt.span, stmt.scope), - None => (data.terminator().span, data.terminator().scope) + Some(stmt) => stmt.source_info, + None => data.terminator().source_info } } - pub fn context_for_location(&self, mir: &Mir, loc: Location) -> (Span, ScopeId) { + pub fn source_info_for_location(&self, mir: &Mir, loc: Location) -> SourceInfo { let data = match loc.block.index().checked_sub(mir.basic_blocks.len()) { Some(new) => &self.new_blocks[new], None => mir.basic_block_data(loc.block) }; - Self::context_for_index(data, loc) + Self::source_info_for_index(data, loc) } } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 49fa1896ff8dd..1380e0b45f279 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -42,6 +42,7 @@ use rustc::hir::fold::{Folder, noop_fold_pat}; use rustc::hir::print::pat_to_string; use syntax::ptr::P; use rustc::util::nodemap::FnvHashMap; +use rustc::util::common::slice_pat; pub const DUMMY_WILD_PAT: &'static Pat = &Pat { id: DUMMY_NODE_ID, @@ -49,7 +50,7 @@ pub const DUMMY_WILD_PAT: &'static Pat = &Pat { span: DUMMY_SP }; -struct Matrix<'a>(Vec>); +struct Matrix<'a, 'tcx>(Vec>)>>); /// Pretty-printer for matrices of patterns, example: /// ++++++++++++++++++++++++++ @@ -63,14 +64,14 @@ struct Matrix<'a>(Vec>); /// ++++++++++++++++++++++++++ /// + _ + [_, _, ..tail] + /// ++++++++++++++++++++++++++ -impl<'a> fmt::Debug for Matrix<'a> { +impl<'a, 'tcx> fmt::Debug for Matrix<'a, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "\n")?; let &Matrix(ref m) = self; let pretty_printed_matrix: Vec> = m.iter().map(|row| { row.iter() - .map(|&pat| pat_to_string(&pat)) + .map(|&(pat,ty)| format!("{}: {:?}", pat_to_string(&pat), ty)) .collect::>() }).collect(); @@ -97,8 +98,10 @@ impl<'a> fmt::Debug for Matrix<'a> { } } -impl<'a> FromIterator> for Matrix<'a> { - fn from_iter>>(iter: T) -> Matrix<'a> { +impl<'a, 'tcx> FromIterator>)>> for Matrix<'a, 'tcx> { + fn from_iter>)>>>(iter: T) + -> Self + { Matrix(iter.into_iter().collect()) } } @@ -109,7 +112,7 @@ pub struct MatchCheckCtxt<'a, 'tcx: 'a> { pub param_env: ParameterEnvironment<'tcx>, } -#[derive(Clone, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum Constructor { /// The constructor of all patterns that don't vary by constructor, /// e.g. struct patterns and fixed-length arrays. @@ -229,7 +232,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) { .iter() .filter(|&&(_, guard)| guard.is_none()) .flat_map(|arm| &arm.0) - .map(|pat| vec![&**pat]) + .map(|pat| vec![wrap_pat(cx, &pat)]) .collect(); check_exhaustive(cx, ex.span, &matrix, source); }, @@ -301,7 +304,7 @@ fn check_arms(cx: &MatchCheckCtxt, let mut printed_if_let_err = false; for &(ref pats, guard) in arms { for pat in pats { - let v = vec![&**pat]; + let v = vec![wrap_pat(cx, &pat)]; match is_useful(cx, &seen, &v[..], LeaveOutWitness) { NotUseful => { @@ -341,8 +344,9 @@ fn check_arms(cx: &MatchCheckCtxt, "unreachable pattern"); // if we had a catchall pattern, hint at that for row in &seen.0 { - if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0]) { - span_note!(err, row[0].span, "this pattern matches any value"); + if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0].0) { + span_note!(err, row[0].0.span, + "this pattern matches any value"); } } err.emit(); @@ -383,20 +387,23 @@ fn raw_pat(p: &Pat) -> &Pat { } } -fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: hir::MatchSource) { - match is_useful(cx, matrix, &[DUMMY_WILD_PAT], ConstructWitness) { +fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, + sp: Span, + matrix: &Matrix<'a, 'tcx>, + source: hir::MatchSource) { + match is_useful(cx, matrix, &[(DUMMY_WILD_PAT, None)], ConstructWitness) { UsefulWithWitness(pats) => { let witnesses = if pats.is_empty() { vec![DUMMY_WILD_PAT] } else { - pats.iter().map(|w| &**w ).collect() + pats.iter().map(|w| &**w).collect() }; match source { hir::MatchSource::ForLoopDesugar => { // `witnesses[0]` has the form `Some()`, peel off the `Some` let witness = match witnesses[0].node { - PatKind::TupleStruct(_, ref pats, _) => match &pats[..] { - [ref pat] => &**pat, + PatKind::TupleStruct(_, ref pats, _) => match slice_pat(&&pats[..]) { + &[ref pat] => &**pat, _ => bug!(), }, _ => bug!(), @@ -584,31 +591,19 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, } } - ty::TyRef(_, ty::TypeAndMut { ty, mutbl }) => { - match ty.sty { - ty::TyArray(_, n) => match ctor { - &Single => { - assert_eq!(pats_len, n); - PatKind::Vec(pats.collect(), None, hir::HirVec::new()) - }, - _ => bug!() - }, - ty::TySlice(_) => match ctor { - &Slice(n) => { - assert_eq!(pats_len, n); - PatKind::Vec(pats.collect(), None, hir::HirVec::new()) - }, - _ => bug!() - }, - ty::TyStr => PatKind::Wild, - - _ => { - assert_eq!(pats_len, 1); - PatKind::Ref(pats.nth(0).unwrap(), mutbl) - } - } + ty::TyRef(_, ty::TypeAndMut { mutbl, .. }) => { + assert_eq!(pats_len, 1); + PatKind::Ref(pats.nth(0).unwrap(), mutbl) } + ty::TySlice(_) => match ctor { + &Slice(n) => { + assert_eq!(pats_len, n); + PatKind::Vec(pats.collect(), None, hir::HirVec::new()) + }, + _ => unreachable!() + }, + ty::TyArray(_, len) => { assert_eq!(pats_len, len); PatKind::Vec(pats.collect(), None, hir::HirVec::new()) @@ -643,7 +638,7 @@ impl Constructor { fn missing_constructors(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix, left_ty: Ty, max_slice_length: usize) -> Vec { let used_constructors: Vec = rows.iter() - .flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length)) + .flat_map(|row| pat_constructors(cx, row[0].0, left_ty, max_slice_length)) .collect(); all_constructors(cx, left_ty, max_slice_length) .into_iter() @@ -660,13 +655,8 @@ fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty, match left_ty.sty { ty::TyBool => [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(), - - ty::TyRef(_, ty::TypeAndMut { ty, .. }) => match ty.sty { - ty::TySlice(_) => - (0..max_slice_length+1).map(|length| Slice(length)).collect(), - _ => vec![Single] - }, - + ty::TySlice(_) => + (0..max_slice_length+1).map(|length| Slice(length)).collect(), ty::TyEnum(def, _) => def.variants.iter().map(|v| Variant(v.did)).collect(), _ => vec![Single] } @@ -685,13 +675,13 @@ fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty, // Note: is_useful doesn't work on empty types, as the paper notes. // So it assumes that v is non-empty. -fn is_useful(cx: &MatchCheckCtxt, - matrix: &Matrix, - v: &[&Pat], - witness: WitnessPreference) - -> Usefulness { +fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, + matrix: &Matrix<'a, 'tcx>, + v: &[(&Pat, Option>)], + witness: WitnessPreference) + -> Usefulness { let &Matrix(ref rows) = matrix; - debug!("{:?}", matrix); + debug!("is_useful({:?}, {:?})", matrix, v); if rows.is_empty() { return match witness { ConstructWitness => UsefulWithWitness(vec!()), @@ -702,32 +692,25 @@ fn is_useful(cx: &MatchCheckCtxt, return NotUseful; } assert!(rows.iter().all(|r| r.len() == v.len())); - let real_pat = match rows.iter().find(|r| (*r)[0].id != DUMMY_NODE_ID) { - Some(r) => raw_pat(r[0]), - None if v.is_empty() => return NotUseful, - None => v[0] - }; - let left_ty = if real_pat.id == DUMMY_NODE_ID { - cx.tcx.mk_nil() - } else { - let left_ty = cx.tcx.pat_ty(&real_pat); - - match real_pat.node { - PatKind::Binding(hir::BindByRef(..), _, _) => { - left_ty.builtin_deref(false, NoPreference).unwrap().ty - } - _ => left_ty, + let left_ty = match rows.iter().filter_map(|r| r[0].1).next().or_else(|| v[0].1) { + Some(ty) => ty, + None => { + // all patterns are wildcards - we can pick any type we want + cx.tcx.types.bool } }; - let max_slice_length = rows.iter().filter_map(|row| match row[0].node { + let max_slice_length = rows.iter().filter_map(|row| match row[0].0.node { PatKind::Vec(ref before, _, ref after) => Some(before.len() + after.len()), _ => None }).max().map_or(0, |v| v + 1); - let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length); + let constructors = pat_constructors(cx, v[0].0, left_ty, max_slice_length); + debug!("is_useful - pat_constructors = {:?} left_ty = {:?}", constructors, + left_ty); if constructors.is_empty() { let constructors = missing_constructors(cx, matrix, left_ty, max_slice_length); + debug!("is_useful - missing_constructors = {:?}", constructors); if constructors.is_empty() { all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| { match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) { @@ -748,7 +731,7 @@ fn is_useful(cx: &MatchCheckCtxt, }).find(|result| result != &NotUseful).unwrap_or(NotUseful) } else { let matrix = rows.iter().filter_map(|r| { - match raw_pat(r[0]).node { + match raw_pat(r[0].0).node { PatKind::Binding(..) | PatKind::Wild => Some(r[1..].to_vec()), _ => None, } @@ -773,9 +756,14 @@ fn is_useful(cx: &MatchCheckCtxt, } } -fn is_useful_specialized(cx: &MatchCheckCtxt, &Matrix(ref m): &Matrix, - v: &[&Pat], ctor: Constructor, lty: Ty, - witness: WitnessPreference) -> Usefulness { +fn is_useful_specialized<'a, 'tcx>( + cx: &MatchCheckCtxt<'a, 'tcx>, + &Matrix(ref m): &Matrix<'a, 'tcx>, + v: &[(&Pat, Option>)], + ctor: Constructor, + lty: Ty<'tcx>, + witness: WitnessPreference) -> Usefulness +{ let arity = constructor_arity(cx, &ctor, lty); let matrix = Matrix(m.iter().filter_map(|r| { specialize(cx, &r[..], &ctor, 0, arity) @@ -818,13 +806,14 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, PatKind::Vec(ref before, ref slice, ref after) => match left_ty.sty { ty::TyArray(_, _) => vec![Single], - _ => if slice.is_some() { + ty::TySlice(_) if slice.is_some() => { (before.len() + after.len()..max_slice_length+1) .map(|length| Slice(length)) .collect() - } else { - vec![Slice(before.len() + after.len())] } + ty::TySlice(_) => vec!(Slice(before.len() + after.len())), + _ => span_bug!(pat.span, "pat_constructors: unexpected \ + slice pattern type {:?}", left_ty) }, PatKind::Box(..) | PatKind::Tuple(..) | PatKind::Ref(..) => vec![Single], @@ -839,18 +828,16 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, /// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3. /// A struct pattern's arity is the number of fields it contains, etc. pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize { + debug!("constructor_arity({:?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs) => fs.len(), ty::TyBox(_) => 1, - ty::TyRef(_, ty::TypeAndMut { ty, .. }) => match ty.sty { - ty::TySlice(_) => match *ctor { - Slice(length) => length, - ConstantValue(_) => 0, - _ => bug!() - }, - ty::TyStr => 0, - _ => 1 + ty::TySlice(_) => match *ctor { + Slice(length) => length, + ConstantValue(_) => 0, + _ => bug!() }, + ty::TyRef(..) => 1, ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { ctor.variant_for_adt(adt).fields.len() } @@ -877,6 +864,19 @@ fn range_covered_by_constructor(ctor: &Constructor, } } +fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>, + pat: &'a Pat) + -> (&'a Pat, Option>) +{ + let pat_ty = cx.tcx.pat_ty(pat); + (pat, Some(match pat.node { + PatKind::Binding(hir::BindByRef(..), _, _) => { + pat_ty.builtin_deref(false, NoPreference).unwrap().ty + } + _ => pat_ty + })) +} + /// This is the main specialization step. It expands the first pattern in the given row /// into `arity` patterns based on the constructor. For most patterns, the step is trivial, /// for instance tuple patterns are flattened and box patterns expand into their inner pattern. @@ -885,14 +885,22 @@ fn range_covered_by_constructor(ctor: &Constructor, /// different patterns. /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing /// fields filled with wild patterns. -pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], - constructor: &Constructor, col: usize, arity: usize) -> Option> { +pub fn specialize<'a, 'b, 'tcx>( + cx: &MatchCheckCtxt<'b, 'tcx>, + r: &[(&'a Pat, Option>)], + constructor: &Constructor, col: usize, arity: usize) + -> Option>)>> +{ + let pat = raw_pat(r[col].0); let &Pat { id: pat_id, ref node, span: pat_span - } = raw_pat(r[col]); - let head: Option> = match *node { + } = pat; + let wpat = |pat: &'a Pat| wrap_pat(cx, pat); + let dummy_pat = (DUMMY_WILD_PAT, None); + + let head: Option)>> = match *node { PatKind::Binding(..) | PatKind::Wild => - Some(vec![DUMMY_WILD_PAT; arity]), + Some(vec![dummy_pat; arity]), PatKind::Path(..) => { let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def(); @@ -917,12 +925,14 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], Def::Variant(..) | Def::Struct(..) => { match ddpos { Some(ddpos) => { - let mut pats: Vec<_> = args[..ddpos].iter().map(|p| &**p).collect(); - pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len())); - pats.extend(args[ddpos..].iter().map(|p| &**p)); + let mut pats: Vec<_> = args[..ddpos].iter().map(|p| { + wpat(p) + }).collect(); + pats.extend(repeat((DUMMY_WILD_PAT, None)).take(arity - args.len())); + pats.extend(args[ddpos..].iter().map(|p| wpat(p))); Some(pats) } - None => Some(args.iter().map(|p| &**p).collect()) + None => Some(args.iter().map(|p| wpat(p)).collect()) } } _ => None @@ -941,8 +951,8 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], if variant.did == def_variant.did { Some(variant.fields.iter().map(|sf| { match pattern_fields.iter().find(|f| f.node.name == sf.name) { - Some(ref f) => &*f.node.pat, - _ => DUMMY_WILD_PAT + Some(ref f) => wpat(&f.node.pat), + _ => dummy_pat } }).collect()) } else { @@ -951,25 +961,32 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } PatKind::Tuple(ref args, Some(ddpos)) => { - let mut pats: Vec<_> = args[..ddpos].iter().map(|p| &**p).collect(); - pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len())); - pats.extend(args[ddpos..].iter().map(|p| &**p)); + let mut pats: Vec<_> = args[..ddpos].iter().map(|p| wpat(p)).collect(); + pats.extend(repeat(dummy_pat).take(arity - args.len())); + pats.extend(args[ddpos..].iter().map(|p| wpat(p))); Some(pats) } PatKind::Tuple(ref args, None) => - Some(args.iter().map(|p| &**p).collect()), + Some(args.iter().map(|p| wpat(&**p)).collect()), PatKind::Box(ref inner) | PatKind::Ref(ref inner, _) => - Some(vec![&**inner]), + Some(vec![wpat(&**inner)]), PatKind::Lit(ref expr) => { - let expr_value = eval_const_expr(cx.tcx, &expr); - match range_covered_by_constructor(constructor, &expr_value, &expr_value) { - Some(true) => Some(vec![]), - Some(false) => None, - None => { - span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms"); - None + if let Some(&ty::TyS { sty: ty::TyRef(_, mt), .. }) = r[col].1 { + // HACK: handle string literals. A string literal pattern + // serves both as an unary reference pattern and as a + // nullary value pattern, depending on the type. + Some(vec![(pat, Some(mt.ty))]) + } else { + let expr_value = eval_const_expr(cx.tcx, &expr); + match range_covered_by_constructor(constructor, &expr_value, &expr_value) { + Some(true) => Some(vec![]), + Some(false) => None, + None => { + span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms"); + None + } } } } @@ -988,37 +1005,45 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } PatKind::Vec(ref before, ref slice, ref after) => { + let pat_len = before.len() + after.len(); match *constructor { - // Fixed-length vectors. Single => { - let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect(); - pats.extend(repeat(DUMMY_WILD_PAT).take(arity - before.len() - after.len())); - pats.extend(after.iter().map(|p| &**p)); - Some(pats) - }, - Slice(length) if before.len() + after.len() <= length && slice.is_some() => { - let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect(); - pats.extend(repeat(DUMMY_WILD_PAT).take(arity - before.len() - after.len())); - pats.extend(after.iter().map(|p| &**p)); - Some(pats) - }, - Slice(length) if before.len() + after.len() == length => { - let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect(); - pats.extend(after.iter().map(|p| &**p)); - Some(pats) + // Fixed-length vectors. + Some( + before.iter().map(|p| wpat(p)).chain( + repeat(dummy_pat).take(arity - pat_len).chain( + after.iter().map(|p| wpat(p)) + )).collect()) }, + Slice(length) if pat_len <= length && slice.is_some() => { + Some( + before.iter().map(|p| wpat(p)).chain( + repeat(dummy_pat).take(arity - pat_len).chain( + after.iter().map(|p| wpat(p)) + )).collect()) + } + Slice(length) if pat_len == length => { + Some( + before.iter().map(|p| wpat(p)).chain( + after.iter().map(|p| wpat(p)) + ).collect()) + } SliceWithSubslice(prefix, suffix) if before.len() == prefix && after.len() == suffix && slice.is_some() => { - let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect(); - pats.extend(after.iter().map(|p| &**p)); + // this is used by trans::_match only + let mut pats: Vec<_> = before.iter() + .map(|p| (&**p, None)).collect(); + pats.extend(after.iter().map(|p| (&**p, None))); Some(pats) } _ => None } } }; + debug!("specialize({:?}, {:?}) = {:?}", r[col], arity, head); + head.map(|mut head| { head.extend_from_slice(&r[..col]); head.extend_from_slice(&r[col + 1..]); @@ -1076,8 +1101,8 @@ fn check_irrefutable(cx: &MatchCheckCtxt, pat: &Pat, is_fn_arg: bool) { fn is_refutable(cx: &MatchCheckCtxt, pat: &Pat, refutable: F) -> Option where F: FnOnce(&Pat) -> A, { - let pats = Matrix(vec!(vec!(pat))); - match is_useful(cx, &pats, &[DUMMY_WILD_PAT], ConstructWitness) { + let pats = Matrix(vec!(vec!(wrap_pat(cx, pat)))); + match is_useful(cx, &pats, &[(DUMMY_WILD_PAT, None)], ConstructWitness) { UsefulWithWitness(pats) => Some(refutable(&pats[0])), NotUseful => None, Useful => bug!() diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 892924db6fad8..b7f14fffafb77 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -16,6 +16,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use middle::const_val::ConstVal; use rustc_const_eval::eval_const_expr_partial; use rustc_const_eval::EvalHint::ExprTypeChecked; +use util::common::slice_pat; use util::nodemap::{FnvHashSet}; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; @@ -459,8 +460,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Check for a repr() attribute to specify the size of the // discriminant. let repr_hints = cx.lookup_repr_hints(def.did); - match &**repr_hints { - [] => { + match slice_pat(&&**repr_hints) { + &[] => { // Special-case types like `Option`. if !is_repr_nullable_ptr(cx, def, substs) { return FfiUnsafe( @@ -470,7 +471,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { the type") } } - [ref hint] => { + &[ref hint] => { if !hint.is_ffi_safe() { // FIXME: This shouldn't be reachable: we should check // this earlier. diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index c1626b93f0c41..7e650c5bd3d06 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -22,7 +22,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast_block: &'tcx hir::Block) -> BlockAnd<()> { let Block { extent, span, stmts, expr } = self.hir.mirror(ast_block); - self.in_scope(extent, block, move |this, _| { + self.in_scope(extent, block, move |this| { // This convoluted structure is to avoid using recursion as we walk down a list // of statements. Basically, the structure we get back is something like: // @@ -40,27 +40,40 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // // First we build all the statements in the block. let mut let_extent_stack = Vec::with_capacity(8); + let outer_visibility_scope = this.visibility_scope; for stmt in stmts { let Stmt { span: _, kind } = this.hir.mirror(stmt); match kind { StmtKind::Expr { scope, expr } => { - unpack!(block = this.in_scope(scope, block, |this, _| { + unpack!(block = this.in_scope(scope, block, |this| { let expr = this.hir.mirror(expr); this.stmt_expr(block, expr) })); } StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => { - let remainder_scope_id = this.push_scope(remainder_scope, block); + let tcx = this.hir.tcx(); + + // Enter the remainder scope, i.e. the bindings' destruction scope. + this.push_scope(remainder_scope, block); let_extent_stack.push(remainder_scope); - unpack!(block = this.in_scope(init_scope, block, move |this, _| { - // FIXME #30046 ^~~~ - if let Some(init) = initializer { - this.expr_into_pattern(block, remainder_scope_id, pattern, init) - } else { - this.declare_bindings(remainder_scope_id, &pattern); - block.unit() - } - })); + + // Declare the bindings, which may create a visibility scope. + let remainder_span = remainder_scope.span(&tcx.region_maps, &tcx.map); + let remainder_span = remainder_span.unwrap_or(span); + let scope = this.declare_bindings(None, remainder_span, &pattern); + + // Evaluate the initializer, if present. + if let Some(init) = initializer { + unpack!(block = this.in_scope(init_scope, block, move |this| { + // FIXME #30046 ^~~~ + this.expr_into_pattern(block, pattern, init) + })); + } + + // Enter the visibility scope, after evaluating the initializer. + if let Some(visibility_scope) = scope { + this.visibility_scope = visibility_scope; + } } } } @@ -70,14 +83,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { unpack!(block = this.into(destination, block, expr)); } else if dest_is_unit { // FIXME(#31472) - let scope_id = this.innermost_scope_id(); - this.cfg.push_assign_unit(block, scope_id, span, destination); + let source_info = this.source_info(span); + this.cfg.push_assign_unit(block, source_info, destination); } // Finally, we pop all the let scopes before exiting out from the scope of block // itself. for extent in let_extent_stack.into_iter().rev() { unpack!(block = this.pop_scope(extent, block)); } + // Restore the original visibility scope. + this.visibility_scope = outer_visibility_scope; block.unit() }) } diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 4859257f291c9..95f87bf832614 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -15,7 +15,6 @@ use build::{CFG, Location}; use rustc::mir::repr::*; -use syntax::codemap::Span; impl<'tcx> CFG<'tcx> { pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> { @@ -50,47 +49,41 @@ impl<'tcx> CFG<'tcx> { pub fn push_assign(&mut self, block: BasicBlock, - scope: ScopeId, - span: Span, + source_info: SourceInfo, lvalue: &Lvalue<'tcx>, rvalue: Rvalue<'tcx>) { self.push(block, Statement { - scope: scope, - span: span, + source_info: source_info, kind: StatementKind::Assign(lvalue.clone(), rvalue) }); } pub fn push_assign_constant(&mut self, block: BasicBlock, - scope: ScopeId, - span: Span, + source_info: SourceInfo, temp: &Lvalue<'tcx>, constant: Constant<'tcx>) { - self.push_assign(block, scope, span, temp, + self.push_assign(block, source_info, temp, Rvalue::Use(Operand::Constant(constant))); } pub fn push_assign_unit(&mut self, block: BasicBlock, - scope: ScopeId, - span: Span, + source_info: SourceInfo, lvalue: &Lvalue<'tcx>) { - self.push_assign(block, scope, span, lvalue, Rvalue::Aggregate( + self.push_assign(block, source_info, lvalue, Rvalue::Aggregate( AggregateKind::Tuple, vec![] )); } pub fn terminate(&mut self, block: BasicBlock, - scope: ScopeId, - span: Span, + source_info: SourceInfo, kind: TerminatorKind<'tcx>) { debug_assert!(self.block_data(block).terminator.is_none(), "terminate: block {:?} already has a terminator set", block); self.block_data_mut(block).terminator = Some(Terminator { - span: span, - scope: scope, + source_info: source_info, kind: kind, }); } diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index bb5aca2d8d7c3..8e33cfa9b0b52 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -34,11 +34,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("expr_as_lvalue(block={:?}, expr={:?})", block, expr); let this = self; - let scope_id = this.innermost_scope_id(); let expr_span = expr.span; + let source_info = this.source_info(expr_span); match expr.kind { ExprKind::Scope { extent, value } => { - this.in_scope(extent, block, |this, _| this.as_lvalue(block, value)) + this.in_scope(extent, block, |this| this.as_lvalue(block, value)) } ExprKind::Field { lhs, name } => { let lvalue = unpack!(block = this.as_lvalue(block, lhs)); @@ -59,9 +59,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // bounds check: let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty)); - this.cfg.push_assign(block, scope_id, expr_span, // len = len(slice) + this.cfg.push_assign(block, source_info, // len = len(slice) &len, Rvalue::Len(slice.clone())); - this.cfg.push_assign(block, scope_id, expr_span, // lt = idx < len + this.cfg.push_assign(block, source_info, // lt = idx < len <, Rvalue::BinaryOp(BinOp::Lt, idx.clone(), Operand::Consume(len.clone()))); diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs index a059f2bdde9c7..beb9ca256abfd 100644 --- a/src/librustc_mir/build/expr/as_operand.rs +++ b/src/librustc_mir/build/expr/as_operand.rs @@ -35,7 +35,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let this = self; if let ExprKind::Scope { extent, value } = expr.kind { - return this.in_scope(extent, block, |this, _| this.as_operand(block, value)); + return this.in_scope(extent, block, |this| this.as_operand(block, value)); } let category = Category::of(&expr.kind).unwrap(); diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 67cf5473f79c0..6524124c13b06 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -41,12 +41,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr); let this = self; - let scope_id = this.innermost_scope_id(); let expr_span = expr.span; + let source_info = this.source_info(expr_span); match expr.kind { ExprKind::Scope { extent, value } => { - this.in_scope(extent, block, |this, _| this.as_rvalue(block, value)) + this.in_scope(extent, block, |this| this.as_rvalue(block, value)) } ExprKind::InlineAsm { asm, outputs, inputs } => { let outputs = outputs.into_iter().map(|output| { @@ -86,7 +86,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let minval = this.minval_literal(expr_span, expr.ty); let is_min = this.temp(bool_ty); - this.cfg.push_assign(block, scope_id, expr_span, &is_min, + this.cfg.push_assign(block, source_info, &is_min, Rvalue::BinaryOp(BinOp::Eq, arg.clone(), minval)); let err = ConstMathErr::Overflow(Op::Neg); @@ -99,8 +99,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let value = this.hir.mirror(value); let result = this.temp(expr.ty); // to start, malloc some memory of suitable type (thus far, uninitialized): - this.cfg.push_assign(block, scope_id, expr_span, &result, Rvalue::Box(value.ty)); - this.in_scope(value_extents, block, |this, _| { + this.cfg.push_assign(block, source_info, &result, Rvalue::Box(value.ty)); + this.in_scope(value_extents, block, |this| { // schedule a shallow free of that memory, lest we unwind: this.schedule_box_free(expr_span, value_extents, &result, value.ty); // initialize the box contents: @@ -245,13 +245,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn build_binary_op(&mut self, mut block: BasicBlock, op: BinOp, span: Span, ty: ty::Ty<'tcx>, lhs: Operand<'tcx>, rhs: Operand<'tcx>) -> BlockAnd> { - let scope_id = self.innermost_scope_id(); + let source_info = self.source_info(span); let bool_ty = self.hir.bool_ty(); if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() { let result_tup = self.hir.tcx().mk_tup(vec![ty, bool_ty]); let result_value = self.temp(result_tup); - self.cfg.push_assign(block, scope_id, span, + self.cfg.push_assign(block, source_info, &result_value, Rvalue::CheckedBinaryOp(op, lhs, rhs)); @@ -292,7 +292,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Check for / 0 let is_zero = self.temp(bool_ty); let zero = self.zero_literal(span, ty); - self.cfg.push_assign(block, scope_id, span, &is_zero, + self.cfg.push_assign(block, source_info, &is_zero, Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), zero)); block = self.assert(block, Operand::Consume(is_zero), false, @@ -310,14 +310,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead - self.cfg.push_assign(block, scope_id, span, &is_neg_1, + self.cfg.push_assign(block, source_info, &is_neg_1, Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), neg_1)); - self.cfg.push_assign(block, scope_id, span, &is_min, + self.cfg.push_assign(block, source_info, &is_min, Rvalue::BinaryOp(BinOp::Eq, lhs.clone(), min)); let is_neg_1 = Operand::Consume(is_neg_1); let is_min = Operand::Consume(is_min); - self.cfg.push_assign(block, scope_id, span, &of, + self.cfg.push_assign(block, source_info, &of, Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min)); block = self.assert(block, Operand::Consume(of), false, diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index f33d3dd5190d9..da128b8dd5626 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -30,7 +30,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let this = self; if let ExprKind::Scope { extent, value } = expr.kind { - return this.in_scope(extent, block, |this, _| this.as_temp(block, value)); + return this.in_scope(extent, block, |this| this.as_temp(block, value)); } let expr_ty = expr.ty.clone(); @@ -49,8 +49,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Category::Lvalue => { let lvalue = unpack!(block = this.as_lvalue(block, expr)); let rvalue = Rvalue::Use(Operand::Consume(lvalue)); - let scope_id = this.innermost_scope_id(); - this.cfg.push_assign(block, scope_id, expr_span, &temp, rvalue); + let source_info = this.source_info(expr_span); + this.cfg.push_assign(block, source_info, &temp, rvalue); } _ => { unpack!(block = this.into(&temp, block, expr)); diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 41610c90377b5..fd9ddc05ab5c4 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -33,11 +33,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // just use the name `this` uniformly let this = self; let expr_span = expr.span; - let scope_id = this.innermost_scope_id(); + let source_info = this.source_info(expr_span); match expr.kind { ExprKind::Scope { extent, value } => { - this.in_scope(extent, block, |this, _| this.into(destination, block, value)) + this.in_scope(extent, block, |this| this.into(destination, block, value)) } ExprKind::Block { body: ast_block } => { this.ast_block(destination, expr.ty.is_nil(), block, ast_block) @@ -50,7 +50,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let mut then_block = this.cfg.start_new_block(); let mut else_block = this.cfg.start_new_block(); - this.cfg.terminate(block, scope_id, expr_span, TerminatorKind::If { + this.cfg.terminate(block, source_info, TerminatorKind::If { cond: operand, targets: (then_block, else_block) }); @@ -61,19 +61,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } else { // Body of the `if` expression without an `else` clause must return `()`, thus // we implicitly generate a `else {}` if it is not specified. - let scope_id = this.innermost_scope_id(); - this.cfg.push_assign_unit(else_block, scope_id, expr_span, destination); + this.cfg.push_assign_unit(else_block, source_info, destination); else_block }; let join_block = this.cfg.start_new_block(); - this.cfg.terminate(then_block, - scope_id, - expr_span, + this.cfg.terminate(then_block, source_info, TerminatorKind::Goto { target: join_block }); - this.cfg.terminate(else_block, - scope_id, - expr_span, + this.cfg.terminate(else_block, source_info, TerminatorKind::Goto { target: join_block }); join_block.unit() @@ -100,19 +95,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { LogicalOp::And => (else_block, false_block), LogicalOp::Or => (true_block, else_block), }; - this.cfg.terminate(block, - scope_id, - expr_span, + this.cfg.terminate(block, source_info, TerminatorKind::If { cond: lhs, targets: blocks }); let rhs = unpack!(else_block = this.as_operand(else_block, rhs)); - this.cfg.terminate(else_block, scope_id, expr_span, TerminatorKind::If { + this.cfg.terminate(else_block, source_info, TerminatorKind::If { cond: rhs, targets: (true_block, false_block) }); this.cfg.push_assign_constant( - true_block, scope_id, expr_span, destination, + true_block, source_info, destination, Constant { span: expr_span, ty: this.hir.bool_ty(), @@ -120,20 +113,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }); this.cfg.push_assign_constant( - false_block, scope_id, expr_span, destination, + false_block, source_info, destination, Constant { span: expr_span, ty: this.hir.bool_ty(), literal: this.hir.false_literal(), }); - this.cfg.terminate(true_block, - scope_id, - expr_span, + this.cfg.terminate(true_block, source_info, TerminatorKind::Goto { target: join_block }); - this.cfg.terminate(false_block, - scope_id, - expr_span, + this.cfg.terminate(false_block, source_info, TerminatorKind::Goto { target: join_block }); join_block.unit() @@ -158,9 +147,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let exit_block = this.cfg.start_new_block(); // start the loop - this.cfg.terminate(block, - scope_id, - expr_span, + this.cfg.terminate(block, source_info, TerminatorKind::Goto { target: loop_block }); let might_break = this.in_loop_scope(loop_block, exit_block, move |this| { @@ -173,9 +160,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let loop_block_end; let cond = unpack!(loop_block_end = this.as_operand(loop_block, cond_expr)); body_block = this.cfg.start_new_block(); - this.cfg.terminate(loop_block_end, - scope_id, - expr_span, + this.cfg.terminate(loop_block_end, source_info, TerminatorKind::If { cond: cond, targets: (body_block, exit_block) @@ -192,15 +177,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let tmp = this.get_unit_temp(); // Execute the body, branching back to the test. let body_block_end = unpack!(this.into(&tmp, body_block, body)); - this.cfg.terminate(body_block_end, - scope_id, - expr_span, + this.cfg.terminate(body_block_end, source_info, TerminatorKind::Goto { target: loop_block }); }); // If the loop may reach its exit_block, we assign an empty tuple to the // destination to keep the MIR well-formed. if might_break { - this.cfg.push_assign_unit(exit_block, scope_id, expr_span, destination); + this.cfg.push_assign_unit(exit_block, source_info, destination); } exit_block.unit() } @@ -219,7 +202,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let success = this.cfg.start_new_block(); let cleanup = this.diverge_cleanup(); - this.cfg.terminate(block, scope_id, expr_span, TerminatorKind::Call { + this.cfg.terminate(block, source_info, TerminatorKind::Call { func: fun, args: args, cleanup: cleanup, @@ -269,7 +252,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }); let rvalue = unpack!(block = this.as_rvalue(block, expr)); - this.cfg.push_assign(block, scope_id, expr_span, destination, rvalue); + this.cfg.push_assign(block, source_info, destination, rvalue); block.unit() } } diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 24369aaff3f5c..ad55a3d8b73f2 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -20,18 +20,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<()> { let this = self; let expr_span = expr.span; - let scope_id = this.innermost_scope_id(); + let source_info = this.source_info(expr.span); // Handle a number of expressions that don't need a destination at all. This // avoids needing a mountain of temporary `()` variables. match expr.kind { ExprKind::Scope { extent, value } => { let value = this.hir.mirror(value); - this.in_scope(extent, block, |this, _| this.stmt_expr(block, value)) + this.in_scope(extent, block, |this| this.stmt_expr(block, value)) } ExprKind::Assign { lhs, rhs } => { let lhs = this.hir.mirror(lhs); let rhs = this.hir.mirror(rhs); - let scope_id = this.innermost_scope_id(); let lhs_span = lhs.span; // Note: we evaluate assignments right-to-left. This @@ -50,7 +49,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } else { let rhs = unpack!(block = this.as_rvalue(block, rhs)); let lhs = unpack!(block = this.as_lvalue(block, lhs)); - this.cfg.push_assign(block, scope_id, expr_span, &lhs, rhs); + this.cfg.push_assign(block, source_info, &lhs, rhs); block.unit() } } @@ -75,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // (overloaded ops should be desugared into a call). let result = unpack!(block = this.build_binary_op(block, op, expr_span, lhs_ty, Operand::Consume(lhs.clone()), rhs)); - this.cfg.push_assign(block, scope_id, expr_span, &lhs, result); + this.cfg.push_assign(block, source_info, &lhs, result); block.unit() } @@ -93,8 +92,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block = match value { Some(value) => unpack!(this.into(&Lvalue::ReturnPointer, block, value)), None => { - this.cfg.push_assign_unit(block, scope_id, - expr_span, &Lvalue::ReturnPointer); + this.cfg.push_assign_unit(block, source_info, &Lvalue::ReturnPointer); block } }; @@ -104,7 +102,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.cfg.start_new_block().unit() } _ => { - let expr_span = expr.span; let expr_ty = expr.ty; let temp = this.temp(expr.ty.clone()); unpack!(block = this.into(&temp, block, expr)); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 88d7e41bc616f..14b4dbdd9cff4 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -44,21 +44,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .collect(), }; - // Get the body expressions and their scopes, while declaring bindings. - let arm_bodies: Vec<_> = arms.iter().enumerate().map(|(i, arm)| { - // Assume that all expressions are wrapped in Scope. + // Get the arm bodies and their scopes, while declaring bindings. + let arm_bodies: Vec<_> = arms.iter().map(|arm| { let body = self.hir.mirror(arm.body.clone()); - match body.kind { - ExprKind::Scope { extent, value } => { - let scope_id = self.push_scope(extent, arm_blocks.blocks[i]); - self.declare_bindings(scope_id, &arm.patterns[0]); - (extent, self.scopes.pop().unwrap(), value) - } - _ => { - span_bug!(body.span, "arm body is not wrapped in Scope {:?}", - body.kind); - } - } + let scope = self.declare_bindings(None, body.span, &arm.patterns[0]); + (body, scope.unwrap_or(self.visibility_scope)) }).collect(); // assemble a list of candidates: there is one candidate per @@ -99,63 +89,46 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // all the arm blocks will rejoin here let end_block = self.cfg.start_new_block(); - let scope_id = self.innermost_scope_id(); - for (arm_index, (extent, scope, body)) in arm_bodies.into_iter().enumerate() { + let outer_source_info = self.source_info(span); + for (arm_index, (body, visibility_scope)) in arm_bodies.into_iter().enumerate() { let mut arm_block = arm_blocks.blocks[arm_index]; - // Re-enter the scope we created the bindings in. - self.scopes.push(scope); + // Re-enter the visibility scope we created the bindings in. + self.visibility_scope = visibility_scope; unpack!(arm_block = self.into(destination, arm_block, body)); - unpack!(arm_block = self.pop_scope(extent, arm_block)); - self.cfg.terminate(arm_block, - scope_id, - span, + self.cfg.terminate(arm_block, outer_source_info, TerminatorKind::Goto { target: end_block }); } + self.visibility_scope = outer_source_info.scope; end_block.unit() } pub fn expr_into_pattern(&mut self, mut block: BasicBlock, - var_scope_id: ScopeId, // lifetime of vars irrefutable_pat: Pattern<'tcx>, initializer: ExprRef<'tcx>) -> BlockAnd<()> { // optimize the case of `let x = ...` match *irrefutable_pat.kind { - PatternKind::Binding { mutability, - name, - mode: BindingMode::ByValue, + PatternKind::Binding { mode: BindingMode::ByValue, var, - ty, - subpattern: None } => { - let index = self.declare_binding(var_scope_id, - mutability, - name, - var, - ty, - irrefutable_pat.span); - let lvalue = Lvalue::Var(index); + subpattern: None, .. } => { + let lvalue = Lvalue::Var(self.var_indices[&var]); return self.into(&lvalue, block, initializer); } _ => {} } let lvalue = unpack!(block = self.as_lvalue(block, initializer)); self.lvalue_into_pattern(block, - var_scope_id, irrefutable_pat, &lvalue) } pub fn lvalue_into_pattern(&mut self, mut block: BasicBlock, - var_scope_id: ScopeId, irrefutable_pat: Pattern<'tcx>, initializer: &Lvalue<'tcx>) -> BlockAnd<()> { - // first, creating the bindings - self.declare_bindings(var_scope_id, &irrefutable_pat); - // create a dummy candidate let mut candidate = Candidate { span: irrefutable_pat.span, @@ -182,32 +155,47 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.unit() } - pub fn declare_bindings(&mut self, var_scope_id: ScopeId, pattern: &Pattern<'tcx>) { + /// Declares the bindings of the given pattern and returns the visibility scope + /// for the bindings in this patterns, if such a scope had to be created. + /// NOTE: Declaring the bindings should always be done in their drop scope. + pub fn declare_bindings(&mut self, + mut var_scope: Option, + scope_span: Span, + pattern: &Pattern<'tcx>) + -> Option { match *pattern.kind { PatternKind::Binding { mutability, name, mode: _, var, ty, ref subpattern } => { - self.declare_binding(var_scope_id, mutability, name, var, ty, pattern.span); + if var_scope.is_none() { + var_scope = Some(self.new_visibility_scope(scope_span)); + } + let source_info = SourceInfo { + span: pattern.span, + scope: var_scope.unwrap() + }; + self.declare_binding(source_info, mutability, name, var, ty); if let Some(subpattern) = subpattern.as_ref() { - self.declare_bindings(var_scope_id, subpattern); + var_scope = self.declare_bindings(var_scope, scope_span, subpattern); } } PatternKind::Array { ref prefix, ref slice, ref suffix } | PatternKind::Slice { ref prefix, ref slice, ref suffix } => { for subpattern in prefix.iter().chain(slice).chain(suffix) { - self.declare_bindings(var_scope_id, subpattern); + var_scope = self.declare_bindings(var_scope, scope_span, subpattern); } } PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => { } PatternKind::Deref { ref subpattern } => { - self.declare_bindings(var_scope_id, subpattern); + var_scope = self.declare_bindings(var_scope, scope_span, subpattern); } PatternKind::Leaf { ref subpatterns } | PatternKind::Variant { ref subpatterns, .. } => { for subpattern in subpatterns { - self.declare_bindings(var_scope_id, &subpattern.pattern); + var_scope = self.declare_bindings(var_scope, scope_span, &subpattern.pattern); } } } + var_scope } } @@ -396,17 +384,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { mut otherwise: Vec) -> BasicBlock { + let source_info = self.source_info(span); otherwise.sort(); otherwise.dedup(); // variant switches can introduce duplicate target blocks - let scope_id = self.innermost_scope_id(); if otherwise.len() == 1 { otherwise[0] } else { let join_block = self.cfg.start_new_block(); for block in otherwise { - self.cfg.terminate(block, - scope_id, - span, + self.cfg.terminate(block, source_info, TerminatorKind::Goto { target: join_block }); } join_block @@ -443,42 +429,87 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// simpler (and, in fact, irrefutable). /// /// But there may also be candidates that the test just doesn't - /// apply to. For example, consider the case of #29740: + /// apply to. The classical example involves wildcards: /// /// ```rust,ignore + /// match (x, y, z) { + /// (true, _, true) => true, // (0) + /// (_, true, _) => true, // (1) + /// (false, false, _) => false, // (2) + /// (true, _, false) => false, // (3) + /// } + /// ``` + /// + /// In that case, after we test on `x`, there are 2 overlapping candidate + /// sets: + /// + /// - If the outcome is that `x` is true, candidates 0, 1, and 3 + /// - If the outcome is that `x` is false, candidates 1 and 2 + /// + /// Here, the traditional "decision tree" method would generate 2 + /// separate code-paths for the 2 separate cases. + /// + /// In some cases, this duplication can create an exponential amount of + /// code. This is most easily seen by noticing that this method terminates + /// with precisely the reachable arms being reachable - but that problem + /// is trivially NP-complete: + /// + /// ```rust + /// match (var0, var1, var2, var3, ..) { + /// (true, _, _, false, true, ...) => false, + /// (_, true, true, false, _, ...) => false, + /// (false, _, false, false, _, ...) => false, + /// ... + /// _ => true + /// } + /// ``` + /// + /// Here the last arm is reachable only if there is an assignment to + /// the variables that does not match any of the literals. Therefore, + /// compilation would take an exponential amount of time in some cases. + /// + /// That kind of exponential worst-case might not occur in practice, but + /// our simplistic treatment of constants and guards would make it occur + /// in very common situations - for example #29740: + /// + /// ```rust /// match x { - /// "foo" => ..., - /// "bar" => ..., - /// "baz" => ..., - /// _ => ..., + /// "foo" if foo_guard => ..., + /// "bar" if bar_guard => ..., + /// "baz" if baz_guard => ..., + /// ... /// } /// ``` /// - /// Here the match-pair we are testing will be `x @ "foo"`, and we - /// will generate an `Eq` test. Because `"bar"` and `"baz"` are different - /// constants, we will decide that these later candidates are just not - /// informed by the eq test. So we'll wind up with three candidate sets: + /// Here we first test the match-pair `x @ "foo"`, which is an `Eq` test. /// - /// - If outcome is that `x == "foo"` (one candidate, derived from `x @ "foo"`) - /// - If outcome is that `x != "foo"` (empty list of candidates) - /// - Otherwise (three candidates, `x @ "bar"`, `x @ "baz"`, `x @ - /// _`). Here we have the invariant that everything in the - /// otherwise list is of **lower priority** than the stuff in the - /// other lists. + /// It might seem that we would end up with 2 disjoint candidate + /// sets, consisting of the first candidate or the other 3, but our + /// algorithm doesn't reason about "foo" being distinct from the other + /// constants; it considers the latter arms to potentially match after + /// both outcomes, which obviously leads to an exponential amount + /// of tests. /// - /// So we'll compile the test. For each outcome of the test, we - /// recursively call `match_candidates` with the corresponding set - /// of candidates. But note that this set is now inexhaustive: for - /// example, in the case where the test returns false, there are - /// NO candidates, even though there is stll a value to be - /// matched. So we'll collect the return values from - /// `match_candidates`, which are the blocks where control-flow - /// goes if none of the candidates matched. At this point, we can - /// continue with the "otherwise" list. + /// To avoid these kinds of problems, our algorithm tries to ensure + /// the amount of generated tests is linear. When we do a k-way test, + /// we return an additional "unmatched" set alongside the obvious `k` + /// sets. When we encounter a candidate that would be present in more + /// than one of the sets, we put it and all candidates below it into the + /// "unmatched" set. This ensures these `k+1` sets are disjoint. + /// + /// After we perform our test, we branch into the appropriate candidate + /// set and recurse with `match_candidates`. These sub-matches are + /// obviously inexhaustive - as we discarded our otherwise set - so + /// we set their continuation to do `match_candidates` on the + /// "unmatched" set (which is again inexhaustive). /// /// If you apply this to the above test, you basically wind up /// with an if-else-if chain, testing each candidate in turn, /// which is precisely what we want. + /// + /// In addition to avoiding exponential-time blowups, this algorithm + /// also has nice property that each guard and arm is only generated + /// once. fn test_candidates<'pat>(&mut self, span: Span, arm_blocks: &mut ArmBlocks, @@ -585,24 +616,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let arm_block = arm_blocks.blocks[candidate.arm_index]; - let scope_id = self.innermost_scope_id(); if let Some(guard) = candidate.guard { // the block to branch to if the guard fails; if there is no // guard, this block is simply unreachable let guard = self.hir.mirror(guard); - let guard_span = guard.span; + let source_info = self.source_info(guard.span); let cond = unpack!(block = self.as_operand(block, guard)); let otherwise = self.cfg.start_new_block(); - self.cfg.terminate(block, - scope_id, - guard_span, + self.cfg.terminate(block, source_info, TerminatorKind::If { cond: cond, targets: (arm_block, otherwise)}); Some(otherwise) } else { - self.cfg.terminate(block, - scope_id, - candidate.span, + let source_info = self.source_info(candidate.span); + self.cfg.terminate(block, source_info, TerminatorKind::Goto { target: arm_block }); None } @@ -628,35 +655,33 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Rvalue::Ref(region, borrow_kind, binding.source), }; - let scope_id = self.innermost_scope_id(); - self.cfg.push_assign(block, scope_id, binding.span, + let source_info = self.source_info(binding.span); + self.cfg.push_assign(block, source_info, &Lvalue::Var(var_index), rvalue); } } fn declare_binding(&mut self, - var_scope_id: ScopeId, + source_info: SourceInfo, mutability: Mutability, name: Name, var_id: NodeId, - var_ty: Ty<'tcx>, - span: Span) + var_ty: Ty<'tcx>) -> u32 { - debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, var_scope_id={:?}, span={:?})", - var_id, name, var_ty, var_scope_id, span); + debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, source_info={:?})", + var_id, name, var_ty, source_info); let index = self.var_decls.len(); self.var_decls.push(VarDecl::<'tcx> { - scope: var_scope_id, + source_info: source_info, mutability: mutability, name: name, ty: var_ty.clone(), - span: span, }); let index = index as u32; - let extent = self.scope_auxiliary[var_scope_id].extent; - self.schedule_drop(span, extent, &Lvalue::Var(index), var_ty); + let extent = self.extent_of_innermost_scope(); + self.schedule_drop(source_info.span, extent, &Lvalue::Var(index), var_ty); self.var_indices.insert(var_id, index); debug!("declare_binding: index={:?}", index); diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index c707bb8a27b6f..8392248e3f22e 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -31,7 +31,7 @@ use std::mem; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn simplify_candidate<'pat>(&mut self, - mut block: BasicBlock, + block: BasicBlock, candidate: &mut Candidate<'pat, 'tcx>) -> BlockAnd<()> { // repeatedly simplify match pairs until fixed point is reached @@ -39,10 +39,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]); let mut progress = match_pairs.len(); // count how many were simplified for match_pair in match_pairs { - match self.simplify_match_pair(block, match_pair, candidate) { - Ok(b) => { - block = b; - } + match self.simplify_match_pair(match_pair, candidate) { + Ok(()) => {} Err(match_pair) => { candidate.match_pairs.push(match_pair); progress -= 1; // this one was not simplified @@ -61,14 +59,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// possible, Err is returned and no changes are made to /// candidate. fn simplify_match_pair<'pat>(&mut self, - mut block: BasicBlock, match_pair: MatchPair<'pat, 'tcx>, candidate: &mut Candidate<'pat, 'tcx>) - -> Result> { + -> Result<(), MatchPair<'pat, 'tcx>> { match *match_pair.pattern.kind { PatternKind::Wild => { // nothing left to do - Ok(block) + Ok(()) } PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => { @@ -87,7 +84,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern)); } - Ok(block) + Ok(()) } PatternKind::Constant { .. } => { @@ -96,37 +93,31 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } PatternKind::Range { .. } | - PatternKind::Variant { .. } => { - // cannot simplify, test is required - Err(match_pair) - } - - PatternKind::Slice { .. } if !match_pair.slice_len_checked => { + PatternKind::Variant { .. } | + PatternKind::Slice { .. } => { Err(match_pair) } - PatternKind::Array { ref prefix, ref slice, ref suffix } | - PatternKind::Slice { ref prefix, ref slice, ref suffix } => { - unpack!(block = self.prefix_suffix_slice(&mut candidate.match_pairs, - block, - match_pair.lvalue.clone(), - prefix, - slice.as_ref(), - suffix)); - Ok(block) + PatternKind::Array { ref prefix, ref slice, ref suffix } => { + self.prefix_slice_suffix(&mut candidate.match_pairs, + &match_pair.lvalue, + prefix, + slice.as_ref(), + suffix); + Ok(()) } PatternKind::Leaf { ref subpatterns } => { // tuple struct, match subpats (if any) candidate.match_pairs .extend(self.field_match_pairs(match_pair.lvalue, subpatterns)); - Ok(block) + Ok(()) } PatternKind::Deref { ref subpattern } => { let lvalue = match_pair.lvalue.deref(); candidate.match_pairs.push(MatchPair::new(lvalue, subpattern)); - Ok(block) + Ok(()) } } } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 09c146537e7d4..668bdcf735802 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; use rustc::mir::repr::*; use syntax::codemap::Span; +use std::cmp::Ordering; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Identifies what test is needed to decide if `match_pair` is applicable. @@ -176,7 +177,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { lvalue: &Lvalue<'tcx>, test: &Test<'tcx>) -> Vec { - let scope_id = self.innermost_scope_id(); + let source_info = self.source_info(test.span); match test.kind { TestKind::Switch { adt_def, ref variants } => { let num_enum_variants = self.hir.num_variants(adt_def); @@ -193,7 +194,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }).collect(); debug!("num_enum_variants: {}, num tested variants: {}, variants: {:?}", num_enum_variants, variants.iter().count(), variants); - self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Switch { + self.cfg.terminate(block, source_info, TerminatorKind::Switch { discr: lvalue.clone(), adt_def: adt_def, targets: target_blocks.clone() @@ -245,10 +246,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } }; - self.cfg.terminate(block, - scope_id, - test.span, - term); + self.cfg.terminate(block, source_info, term); targets } @@ -265,7 +263,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let ty::TyArray(_, _) = mt.ty.sty { ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8)); let val_slice = self.temp(ty); - self.cfg.push_assign(block, scope_id, test.span, &val_slice, + self.cfg.push_assign(block, source_info, &val_slice, Rvalue::Cast(CastKind::Unsize, val, ty)); val = Operand::Consume(val_slice); } @@ -280,7 +278,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }); let slice = self.temp(ty); - self.cfg.push_assign(block, scope_id, test.span, &slice, + self.cfg.push_assign(block, source_info, &slice, Rvalue::Cast(CastKind::Unsize, array, ty)); Operand::Consume(slice) } else { @@ -301,7 +299,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let eq_result = self.temp(bool_ty); let eq_block = self.cfg.start_new_block(); let cleanup = self.diverge_cleanup(); - self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Call { + self.cfg.terminate(block, source_info, TerminatorKind::Call { func: Operand::Constant(Constant { span: test.span, ty: mty, @@ -314,7 +312,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // check the result let block = self.cfg.start_new_block(); - self.cfg.terminate(eq_block, scope_id, test.span, TerminatorKind::If { + self.cfg.terminate(eq_block, source_info, TerminatorKind::If { cond: Operand::Consume(eq_result), targets: (block, fail), }); @@ -344,17 +342,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty)); // actual = len(lvalue) - self.cfg.push_assign(block, scope_id, test.span, + self.cfg.push_assign(block, source_info, &actual, Rvalue::Len(lvalue.clone())); // expected = - let expected = self.push_usize(block, scope_id, test.span, len); + let expected = self.push_usize(block, source_info, len); // result = actual == expected OR result = actual < expected - self.cfg.push_assign(block, - scope_id, - test.span, - &result, + self.cfg.push_assign(block, source_info, &result, Rvalue::BinaryOp(op, Operand::Consume(actual), Operand::Consume(expected))); @@ -362,7 +357,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // branch based on result let target_blocks: Vec<_> = vec![self.cfg.start_new_block(), self.cfg.start_new_block()]; - self.cfg.terminate(block, scope_id, test.span, TerminatorKind::If { + self.cfg.terminate(block, source_info, TerminatorKind::If { cond: Operand::Consume(result), targets: (target_blocks[0], target_blocks[1]) }); @@ -383,13 +378,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let result = self.temp(bool_ty); // result = op(left, right) - let scope_id = self.innermost_scope_id(); - self.cfg.push_assign(block, scope_id, span, &result, + let source_info = self.source_info(span); + self.cfg.push_assign(block, source_info, &result, Rvalue::BinaryOp(op, left, right)); // branch based on result let target_block = self.cfg.start_new_block(); - self.cfg.terminate(block, scope_id, span, TerminatorKind::If { + self.cfg.terminate(block, source_info, TerminatorKind::If { cond: Operand::Consume(result), targets: (target_block, fail_block) }); @@ -452,69 +447,118 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } }; - match test.kind { + match (&test.kind, &*match_pair.pattern.kind) { // If we are performing a variant switch, then this // informs variant patterns, but nothing else. - TestKind::Switch { adt_def: tested_adt_def , .. } => { - match *match_pair.pattern.kind { - PatternKind::Variant { adt_def, variant_index, ref subpatterns } => { - assert_eq!(adt_def, tested_adt_def); - let new_candidate = - self.candidate_after_variant_switch(match_pair_index, - adt_def, - variant_index, - subpatterns, - candidate); - resulting_candidates[variant_index].push(new_candidate); - true - } - _ => { - false - } - } + (&TestKind::Switch { adt_def: tested_adt_def, .. }, + &PatternKind::Variant { adt_def, variant_index, ref subpatterns }) => { + assert_eq!(adt_def, tested_adt_def); + let new_candidate = + self.candidate_after_variant_switch(match_pair_index, + adt_def, + variant_index, + subpatterns, + candidate); + resulting_candidates[variant_index].push(new_candidate); + true } + (&TestKind::Switch { .. }, _) => false, // If we are performing a switch over integers, then this informs integer // equality, but nothing else. // - // FIXME(#29623) we could use TestKind::Range to rule + // FIXME(#29623) we could use PatternKind::Range to rule // things out here, in some cases. - TestKind::SwitchInt { switch_ty: _, options: _, ref indices } => { - match *match_pair.pattern.kind { - PatternKind::Constant { ref value } - if is_switch_ty(match_pair.pattern.ty) => { - let index = indices[value]; - let new_candidate = self.candidate_without_match_pair(match_pair_index, - candidate); - resulting_candidates[index].push(new_candidate); + (&TestKind::SwitchInt { switch_ty: _, options: _, ref indices }, + &PatternKind::Constant { ref value }) + if is_switch_ty(match_pair.pattern.ty) => { + let index = indices[value]; + let new_candidate = self.candidate_without_match_pair(match_pair_index, + candidate); + resulting_candidates[index].push(new_candidate); + true + } + (&TestKind::SwitchInt { .. }, _) => false, + + + (&TestKind::Len { len: test_len, op: BinOp::Eq }, + &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => { + let pat_len = (prefix.len() + suffix.len()) as u64; + match (test_len.cmp(&pat_len), slice) { + (Ordering::Equal, &None) => { + // on true, min_len = len = $actual_length, + // on false, len != $actual_length + resulting_candidates[0].push( + self.candidate_after_slice_test(match_pair_index, + candidate, + prefix, + slice.as_ref(), + suffix) + ); true } - _ => { + (Ordering::Less, _) => { + // test_len < pat_len. If $actual_len = test_len, + // then $actual_len < pat_len and we don't have + // enough elements. + resulting_candidates[1].push(candidate.clone()); + true + } + (Ordering::Equal, &Some(_)) | (Ordering::Greater, &Some(_)) => { + // This can match both if $actual_len = test_len >= pat_len, + // and if $actual_len > test_len. We can't advance. false } + (Ordering::Greater, &None) => { + // test_len != pat_len, so if $actual_len = test_len, then + // $actual_len != pat_len. + resulting_candidates[1].push(candidate.clone()); + true + } } } - // If we are performing a length check, then this - // informs slice patterns, but nothing else. - TestKind::Len { .. } => { - let pattern_test = self.test(&match_pair); - match *match_pair.pattern.kind { - PatternKind::Slice { .. } if pattern_test.kind == test.kind => { - let mut new_candidate = candidate.clone(); - - // Set up the MatchKind to simplify this like an array. - new_candidate.match_pairs[match_pair_index] - .slice_len_checked = true; - resulting_candidates[0].push(new_candidate); + (&TestKind::Len { len: test_len, op: BinOp::Ge }, + &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => { + // the test is `$actual_len >= test_len` + let pat_len = (prefix.len() + suffix.len()) as u64; + match (test_len.cmp(&pat_len), slice) { + (Ordering::Equal, &Some(_)) => { + // $actual_len >= test_len = pat_len, + // so we can match. + resulting_candidates[0].push( + self.candidate_after_slice_test(match_pair_index, + candidate, + prefix, + slice.as_ref(), + suffix) + ); true } - _ => false + (Ordering::Less, _) | (Ordering::Equal, &None) => { + // test_len <= pat_len. If $actual_len < test_len, + // then it is also < pat_len, so the test passing is + // necessary (but insufficient). + resulting_candidates[0].push(candidate.clone()); + true + } + (Ordering::Greater, &None) => { + // test_len > pat_len. If $actual_len >= test_len > pat_len, + // then we know we won't have a match. + resulting_candidates[1].push(candidate.clone()); + true + } + (Ordering::Greater, &Some(_)) => { + // test_len < pat_len, and is therefore less + // strict. This can still go both ways. + false + } } } - TestKind::Eq { .. } | - TestKind::Range { .. } => { + (&TestKind::Eq { .. }, _) | + (&TestKind::Range { .. }, _) | + (&TestKind::Len { .. }, _) => { // These are all binary tests. // // FIXME(#29623) we can be more clever here @@ -550,6 +594,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } + fn candidate_after_slice_test<'pat>(&mut self, + match_pair_index: usize, + candidate: &Candidate<'pat, 'tcx>, + prefix: &'pat [Pattern<'tcx>], + opt_slice: Option<&'pat Pattern<'tcx>>, + suffix: &'pat [Pattern<'tcx>]) + -> Candidate<'pat, 'tcx> { + let mut new_candidate = + self.candidate_without_match_pair(match_pair_index, candidate); + self.prefix_slice_suffix( + &mut new_candidate.match_pairs, + &candidate.match_pairs[match_pair_index].lvalue, + prefix, + opt_slice, + suffix); + + new_candidate + } + fn candidate_after_variant_switch<'pat>(&mut self, match_pair_index: usize, adt_def: ty::AdtDef<'tcx>, diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs index 5eb58f7612d74..53ebf6fceb5c8 100644 --- a/src/librustc_mir/build/matches/util.rs +++ b/src/librustc_mir/build/matches/util.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use build::{BlockAnd, BlockAndExtension, Builder}; +use build::Builder; use build::matches::MatchPair; use hair::*; use rustc::mir::repr::*; @@ -28,64 +28,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .collect() } - /// When processing an array/slice pattern like `lv @ [x, y, ..s, z]`, - /// this function converts the prefix (`x`, `y`) and suffix (`z`) into - /// distinct match pairs: - /// - /// ```rust,ignore - /// lv[0 of 3] @ x // see ProjectionElem::ConstantIndex (and its Debug impl) - /// lv[1 of 3] @ y // to explain the `[x of y]` notation - /// lv[-1 of 3] @ z - /// ``` - /// - /// If a slice like `s` is present, then the function also creates - /// a temporary like: - /// - /// ```rust,ignore - /// tmp0 = lv[2..-1] // using the special Rvalue::Slice - /// ``` - /// - /// and creates a match pair `tmp0 @ s` - pub fn prefix_suffix_slice<'pat>(&mut self, + pub fn prefix_slice_suffix<'pat>(&mut self, match_pairs: &mut Vec>, - block: BasicBlock, - lvalue: Lvalue<'tcx>, + lvalue: &Lvalue<'tcx>, prefix: &'pat [Pattern<'tcx>], opt_slice: Option<&'pat Pattern<'tcx>>, - suffix: &'pat [Pattern<'tcx>]) - -> BlockAnd<()> { - // If there is a `..P` pattern, create a temporary `t0` for - // the slice and then a match pair `t0 @ P`: - if let Some(slice) = opt_slice { - let prefix_len = prefix.len(); - let suffix_len = suffix.len(); - let rvalue = Rvalue::Slice { - input: lvalue.clone(), - from_start: prefix_len, - from_end: suffix_len, - }; - let temp = self.temp(slice.ty.clone()); // no need to schedule drop, temp is always copy - let scope_id = self.innermost_scope_id(); - self.cfg.push_assign(block, scope_id, slice.span, &temp, rvalue); - match_pairs.push(MatchPair::new(temp, slice)); - } - - self.prefix_suffix(match_pairs, lvalue, prefix, suffix); - - block.unit() - } - - /// Helper for `prefix_suffix_slice` which just processes the prefix and suffix. - fn prefix_suffix<'pat>(&mut self, - match_pairs: &mut Vec>, - lvalue: Lvalue<'tcx>, - prefix: &'pat [Pattern<'tcx>], - suffix: &'pat [Pattern<'tcx>]) { + suffix: &'pat [Pattern<'tcx>]) { let min_length = prefix.len() + suffix.len(); assert!(min_length < u32::MAX as usize); let min_length = min_length as u32; - let prefix_pairs: Vec<_> = + match_pairs.extend( prefix.iter() .enumerate() .map(|(idx, subpattern)| { @@ -97,9 +50,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let lvalue = lvalue.clone().elem(elem); MatchPair::new(lvalue, subpattern) }) - .collect(); + ); + + if let Some(subslice_pat) = opt_slice { + let subslice = lvalue.clone().elem(ProjectionElem::Subslice { + from: prefix.len() as u32, + to: suffix.len() as u32 + }); + match_pairs.push(MatchPair::new(subslice, subslice_pat)); + } - let suffix_pairs: Vec<_> = + match_pairs.extend( suffix.iter() .rev() .enumerate() @@ -112,9 +73,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let lvalue = lvalue.clone().elem(elem); MatchPair::new(lvalue, subpattern) }) - .collect(); - - match_pairs.extend(prefix_pairs.into_iter().chain(suffix_pairs)); + ); } } diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index c3501140fc0a5..a9d5c0c4f85c3 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -103,16 +103,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn push_usize(&mut self, block: BasicBlock, - scope_id: ScopeId, - span: Span, + source_info: SourceInfo, value: u64) -> Lvalue<'tcx> { let usize_ty = self.hir.usize_ty(); let temp = self.temp(usize_ty); self.cfg.push_assign_constant( - block, scope_id, span, &temp, + block, source_info, &temp, Constant { - span: span, + span: source_info.span, ty: self.hir.usize_ty(), literal: self.hir.usize_literal(value), }); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 9d7818a9ba4d6..9c1b9fa4437e0 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -15,6 +15,7 @@ use rustc::mir::repr::*; use rustc_data_structures::fnv::FnvHashMap; use rustc::hir; use std::ops::{Index, IndexMut}; +use std::u32; use syntax::abi::Abi; use syntax::ast; use syntax::codemap::Span; @@ -43,7 +44,8 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// the vector of all scopes that we have created thus far; /// we track this for debuginfo later - scope_datas: Vec, + visibility_scopes: Vec, + visibility_scope: VisibilityScope, var_decls: Vec>, var_indices: FnvHashMap, @@ -61,6 +63,20 @@ struct CFG<'tcx> { basic_blocks: Vec>, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct ScopeId(u32); + +impl ScopeId { + pub fn new(index: usize) -> ScopeId { + assert!(index < (u32::MAX as usize)); + ScopeId(index as u32) + } + + pub fn index(self) -> usize { + self.0 as usize + } +} + /// For each scope, we track the extent (from the HIR) and a /// single-entry-multiple-exit subgraph that contains all the /// statements/terminators within it. @@ -179,17 +195,16 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, tcx.region_maps.lookup_code_extent( CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id }); let mut block = START_BLOCK; - let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, - |builder, call_site_scope_id| { - let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, - |builder, arg_scope_id| { - builder.args_and_body(block, return_ty, arguments, arg_scope_id, ast_block) + let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, |builder| { + let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, |builder| { + builder.args_and_body(block, return_ty, arguments, arg_extent, ast_block) })); + let source_info = builder.source_info(span); let return_block = builder.return_block(); - builder.cfg.terminate(block, call_site_scope_id, span, + builder.cfg.terminate(block, source_info, TerminatorKind::Goto { target: return_block }); - builder.cfg.terminate(return_block, call_site_scope_id, span, + builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); return_block.and(arg_decls) })); @@ -241,14 +256,15 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, let extent = ROOT_CODE_EXTENT; let mut block = START_BLOCK; - let _ = builder.in_scope(extent, block, |builder, call_site_scope_id| { + let _ = builder.in_scope(extent, block, |builder| { let expr = builder.hir.mirror(ast_expr); unpack!(block = builder.into(&Lvalue::ReturnPointer, block, expr)); + let source_info = builder.source_info(span); let return_block = builder.return_block(); - builder.cfg.terminate(block, call_site_scope_id, span, + builder.cfg.terminate(block, source_info, TerminatorKind::Goto { target: return_block }); - builder.cfg.terminate(return_block, call_site_scope_id, span, + builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); return_block.unit() @@ -265,7 +281,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { cfg: CFG { basic_blocks: vec![] }, fn_span: span, scopes: vec![], - scope_datas: vec![], + visibility_scopes: vec![], + visibility_scope: ARGUMENT_VISIBILITY_SCOPE, scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] }, loop_scopes: vec![], temp_decls: vec![], @@ -277,6 +294,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; assert_eq!(builder.cfg.start_new_block(), START_BLOCK); + assert_eq!(builder.new_visibility_scope(span), ARGUMENT_VISIBILITY_SCOPE); + builder.visibility_scopes[ARGUMENT_VISIBILITY_SCOPE].parent_scope = None; builder } @@ -294,7 +313,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { (Mir { basic_blocks: self.cfg.basic_blocks, - scopes: self.scope_datas, + visibility_scopes: self.visibility_scopes, promoted: vec![], var_decls: self.var_decls, arg_decls: arg_decls, @@ -309,24 +328,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { mut block: BasicBlock, return_ty: ty::FnOutput<'tcx>, arguments: A, - argument_scope_id: ScopeId, + argument_extent: CodeExtent, ast_block: &'gcx hir::Block) -> BlockAnd>> where A: Iterator, Option<&'gcx hir::Pat>)> { // to start, translate the argument patterns and collect the argument types. + let mut scope = None; let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| { let lvalue = Lvalue::Arg(index as u32); if let Some(pattern) = pattern { let pattern = self.hir.irrefutable_pat(pattern); - unpack!(block = self.lvalue_into_pattern(block, - argument_scope_id, - pattern, - &lvalue)); + scope = self.declare_bindings(scope, ast_block.span, &pattern); + unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue)); } // Make sure we drop (parts of) the argument even when not matched on. - let argument_extent = self.scope_auxiliary[argument_scope_id].extent; self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span), argument_extent, &lvalue, ty); @@ -344,6 +361,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } }).collect(); + // Enter the argument pattern bindings visibility scope, if it exists. + if let Some(visibility_scope) = scope { + self.visibility_scope = visibility_scope; + } + // FIXME(#32959): temporary hack for the issue at hand let return_is_unit = if let ty::FnConverging(t) = return_ty { t.is_nil() diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 209649dd2fd18..2b7efa52cbd05 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -86,7 +86,7 @@ should go to. */ -use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary}; +use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId}; use rustc::middle::region::{CodeExtent, CodeExtentData}; use rustc::middle::lang_items; use rustc::ty::subst::{Substs, Subst, VecPerParamSpace}; @@ -98,9 +98,12 @@ use rustc::middle::const_val::ConstVal; use rustc_const_math::ConstInt; pub struct Scope<'tcx> { - /// the scope-id within the scope_datas + /// the scope-id within the scope_auxiliary id: ScopeId, + /// The visibility scope this scope was created in. + visibility_scope: VisibilityScope, + /// the extent of this scope within source code; also stored in /// `ScopeAuxiliary`, but kept here for convenience extent: CodeExtent, @@ -204,6 +207,14 @@ impl<'tcx> Scope<'tcx> { None } } + + /// Given a span and this scope's visibility scope, make a SourceInfo. + fn source_info(&self, span: Span) -> SourceInfo { + SourceInfo { + span: span, + scope: self.visibility_scope + } + } } impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { @@ -237,11 +248,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Convenience wrapper that pushes a scope and then executes `f` /// to build its contents, popping the scope afterwards. pub fn in_scope(&mut self, extent: CodeExtent, mut block: BasicBlock, f: F) -> BlockAnd - where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>, ScopeId) -> BlockAnd + where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd { debug!("in_scope(extent={:?}, block={:?})", extent, block); - let id = self.push_scope(extent, block); - let rv = unpack!(block = f(self, id)); + self.push_scope(extent, block); + let rv = unpack!(block = f(self)); unpack!(block = self.pop_scope(extent, block)); debug!("in_scope: exiting extent={:?} block={:?}", extent, block); block.and(rv) @@ -251,17 +262,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// scope and call `pop_scope` afterwards. Note that these two /// calls must be paired; using `in_scope` as a convenience /// wrapper maybe preferable. - pub fn push_scope(&mut self, extent: CodeExtent, entry: BasicBlock) -> ScopeId { + pub fn push_scope(&mut self, extent: CodeExtent, entry: BasicBlock) { debug!("push_scope({:?})", extent); - let parent_id = self.scopes.last().map(|s| s.id); - let id = ScopeId::new(self.scope_datas.len()); - let tcx = self.hir.tcx(); - self.scope_datas.push(ScopeData { - span: extent.span(&tcx.region_maps, &tcx.map).unwrap_or(DUMMY_SP), - parent_scope: parent_id, - }); + let id = ScopeId::new(self.scope_auxiliary.vec.len()); + let vis_scope = self.visibility_scope; self.scopes.push(Scope { id: id, + visibility_scope: vis_scope, extent: extent, drops: vec![], free: None, @@ -272,7 +279,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { dom: self.cfg.current_location(entry), postdoms: vec![] }); - id } /// Pops a scope, which should have extent `extent`, adding any @@ -320,7 +326,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(ref free_data) = scope.free { let next = self.cfg.start_new_block(); let free = build_free(self.hir.tcx(), &tmp, free_data, next); - self.cfg.terminate(block, scope.id, span, free); + self.cfg.terminate(block, scope.source_info(span), free); block = next; } self.scope_auxiliary[scope.id] @@ -334,11 +340,21 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .next() .unwrap(); self.cfg.terminate(block, - scope.id, - span, + scope.source_info(span), TerminatorKind::Goto { target: target }); } + /// Creates a new visibility scope, nested in the current one. + pub fn new_visibility_scope(&mut self, span: Span) -> VisibilityScope { + let parent = self.visibility_scope; + let scope = VisibilityScope::new(self.visibility_scopes.len()); + self.visibility_scopes.push(VisibilityScopeData { + span: span, + parent_scope: Some(parent), + }); + scope + } + // Finding scopes // ============== /// Finds the loop scope for a given label. This is used for @@ -363,8 +379,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }.unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?")) } - pub fn innermost_scope_id(&self) -> ScopeId { - self.scopes.last().map(|scope| scope.id).unwrap() + /// Given a span and the current visibility scope, make a SourceInfo. + pub fn source_info(&self, span: Span) -> SourceInfo { + SourceInfo { + span: span, + scope: self.visibility_scope + } } pub fn extent_of_innermost_scope(&self) -> CodeExtent { @@ -481,7 +501,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { target } else { let resumeblk = cfg.start_new_cleanup_block(); - cfg.terminate(resumeblk, scopes[0].id, self.fn_span, TerminatorKind::Resume); + cfg.terminate(resumeblk, + scopes[0].source_info(self.fn_span), + TerminatorKind::Resume); *cached_resume_block = Some(resumeblk); resumeblk }; @@ -502,12 +524,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if !self.hir.needs_drop(ty) { return block.unit(); } - let scope_id = self.innermost_scope_id(); + let source_info = self.source_info(span); let next_target = self.cfg.start_new_block(); let diverge_target = self.diverge_cleanup(); - self.cfg.terminate(block, - scope_id, - span, + self.cfg.terminate(block, source_info, TerminatorKind::Drop { location: location, target: next_target, @@ -522,12 +542,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: Span, location: Lvalue<'tcx>, value: Operand<'tcx>) -> BlockAnd<()> { - let scope_id = self.innermost_scope_id(); + let source_info = self.source_info(span); let next_target = self.cfg.start_new_block(); let diverge_target = self.diverge_cleanup(); - self.cfg.terminate(block, - scope_id, - span, + self.cfg.terminate(block, source_info, TerminatorKind::DropAndReplace { location: location, value: value, @@ -562,18 +580,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let elems = vec![Operand::Constant(message), Operand::Constant(file), Operand::Constant(line)]; - let scope_id = self.innermost_scope_id(); + let source_info = self.source_info(span); // FIXME: We should have this as a constant, rather than a stack variable (to not pollute // icache with cold branch code), however to achieve that we either have to rely on rvalue // promotion or have some way, in MIR, to create constants. - self.cfg.push_assign(block, scope_id, span, &tuple, // [1] + self.cfg.push_assign(block, source_info, &tuple, // [1] Rvalue::Aggregate(AggregateKind::Tuple, elems)); // [1] tuple = (message_arg, file_arg, line_arg); // FIXME: is this region really correct here? - self.cfg.push_assign(block, scope_id, span, &tuple_ref, // tuple_ref = &tuple; + self.cfg.push_assign(block, source_info, &tuple_ref, // tuple_ref = &tuple; Rvalue::Ref(region, BorrowKind::Shared, tuple)); let cleanup = self.diverge_cleanup(); - self.cfg.terminate(block, scope_id, span, TerminatorKind::Call { + self.cfg.terminate(block, source_info, TerminatorKind::Call { func: Operand::Constant(func), args: vec![Operand::Consume(tuple_ref)], cleanup: cleanup, @@ -590,12 +608,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { msg: AssertMessage<'tcx>, span: Span) -> BasicBlock { - let scope_id = self.innermost_scope_id(); + let source_info = self.source_info(span); let success_block = self.cfg.start_new_block(); let cleanup = self.diverge_cleanup(); - self.cfg.terminate(block, scope_id, span, + self.cfg.terminate(block, source_info, TerminatorKind::Assert { cond: cond, expected: expected, @@ -658,7 +676,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, earlier_scopes.iter().rev().flat_map(|s| s.cached_block()).next() }); let next = cfg.start_new_block(); - cfg.terminate(block, scope.id, drop_data.span, TerminatorKind::Drop { + cfg.terminate(block, scope.source_info(drop_data.span), TerminatorKind::Drop { location: drop_data.location.clone(), target: next, unwind: on_diverge @@ -688,15 +706,19 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // remainder. If everything is cached, we'll just walk right to // left reading the cached results but never created anything. + let visibility_scope = scope.visibility_scope; + let source_info = |span| SourceInfo { + span: span, + scope: visibility_scope + }; + // Next, build up any free. if let Some(ref mut free_data) = scope.free { target = if let Some(cached_block) = free_data.cached_block { cached_block } else { let into = cfg.start_new_cleanup_block(); - cfg.terminate(into, - scope.id, - free_data.span, + cfg.terminate(into, source_info(free_data.span), build_free(tcx, unit_temp, free_data, target)); free_data.cached_block = Some(into); into @@ -711,9 +733,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cached_block } else { let block = cfg.start_new_cleanup_block(); - cfg.terminate(block, - scope.id, - drop_data.span, + cfg.terminate(block, source_info(drop_data.span), TerminatorKind::Drop { location: drop_data.location.clone(), target: target, diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 79d11e78bde5a..3d1ef31bd5c2a 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -49,4 +49,3 @@ mod hair; pub mod mir_map; pub mod pretty; pub mod transform; -pub mod traversal; diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index a6bbd55ffa7a4..8c21928c2513b 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}; +use build::{Location, ScopeAuxiliaryVec, ScopeId}; use rustc::hir; use rustc::mir::repr::*; use rustc::mir::transform::MirSource; @@ -18,7 +18,6 @@ use std::fmt::Display; use std::fs; use std::io::{self, Write}; use syntax::ast::NodeId; -use syntax::codemap::Span; const INDENT: &'static str = " "; /// Alignment for lining up comments following MIR statements @@ -139,20 +138,11 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, write_mir_intro(tcx, src, mir, w)?; for block in mir.all_basic_blocks() { write_basic_block(tcx, block, mir, w, &annotations)?; + if block.index() + 1 != mir.basic_blocks.len() { + writeln!(w, "")?; + } } - // construct a scope tree and write it out - let mut scope_tree: FnvHashMap, Vec> = FnvHashMap(); - for (index, scope_data) in mir.scopes.iter().enumerate() { - scope_tree.entry(scope_data.parent_scope) - .or_insert(vec![]) - .push(ScopeId::new(index)); - } - - writeln!(w, "{}scope tree:", INDENT)?; - write_scope_tree(tcx, mir, auxiliary, &scope_tree, w, None, 1, false)?; - writeln!(w, "")?; - writeln!(w, "}}")?; Ok(()) } @@ -189,7 +179,7 @@ fn write_basic_block(tcx: TyCtxt, writeln!(w, "{0:1$} // {2}", indented_mir, ALIGN, - comment(tcx, statement.scope, statement.span))?; + comment(tcx, statement.source_info))?; current_location.statement_index += 1; } @@ -199,71 +189,64 @@ fn write_basic_block(tcx: TyCtxt, writeln!(w, "{0:1$} // {2}", indented_terminator, ALIGN, - comment(tcx, data.terminator().scope, data.terminator().span))?; + comment(tcx, data.terminator().source_info))?; writeln!(w, "{}}}\n", INDENT) } -fn comment(tcx: TyCtxt, scope: ScopeId, span: Span) -> String { +fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String { format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span)) } fn write_scope_tree(tcx: TyCtxt, mir: &Mir, - auxiliary: Option<&ScopeAuxiliaryVec>, - scope_tree: &FnvHashMap, Vec>, + scope_tree: &FnvHashMap>, w: &mut Write, - parent: Option, - depth: usize, - same_line: bool) + parent: VisibilityScope, + depth: usize) -> io::Result<()> { - let indent = if same_line { - 0 - } else { - depth * INDENT.len() - }; + let indent = depth * INDENT.len(); let children = match scope_tree.get(&parent) { Some(childs) => childs, None => return Ok(()), }; - for (index, &child) in children.iter().enumerate() { - if index == 0 && same_line { - // We know we're going to output a scope, so prefix it with a space to separate it from - // the previous scopes on this line - write!(w, " ")?; - } - - let data = &mir.scopes[child]; - assert_eq!(data.parent_scope, parent); - write!(w, "{0:1$}{2}", "", indent, child.index())?; + for &child in children { + let data = &mir.visibility_scopes[child]; + assert_eq!(data.parent_scope, Some(parent)); + writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?; - let indent = indent + INDENT.len(); + // User variable types (including the user's name in a comment). + for (i, var) in mir.var_decls.iter().enumerate() { + // Skip if not declared in this scope. + if var.source_info.scope != child { + continue; + } - if let Some(auxiliary) = auxiliary { - let extent = auxiliary[child].extent; - let data = tcx.region_maps.code_extent_data(extent); - writeln!(w, "{0:1$}Extent: {2:?}", "", indent, data)?; + let mut_str = if var.mutability == Mutability::Mut { + "mut " + } else { + "" + }; + + let indent = indent + INDENT.len(); + let indented_var = format!("{0:1$}let {2}{3:?}: {4};", + INDENT, + indent, + mut_str, + Lvalue::Var(i as u32), + var.ty); + writeln!(w, "{0:1$} // \"{2}\" in {3}", + indented_var, + ALIGN, + var.name, + comment(tcx, var.source_info))?; } - let child_count = scope_tree.get(&Some(child)).map(Vec::len).unwrap_or(0); - if child_count < 2 { - // Skip the braces when there's no or only a single subscope - write_scope_tree(tcx, mir, auxiliary, scope_tree, w, - Some(child), depth, true)?; - } else { - // 2 or more child scopes? Put them in braces and on new lines. - writeln!(w, " {{")?; - write_scope_tree(tcx, mir, auxiliary, scope_tree, w, - Some(child), depth + 1, false)?; - - write!(w, "\n{0:1$}}}", "", depth * INDENT.len())?; - } + write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?; - if !same_line && index + 1 < children.len() { - writeln!(w, "")?; - } + writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?; } Ok(()) @@ -278,7 +261,23 @@ fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> io::Result<()> { write_mir_sig(tcx, src, mir, w)?; writeln!(w, " {{")?; - write_mir_decls(tcx, mir, w) + + // construct a scope tree and write it out + let mut scope_tree: FnvHashMap> = FnvHashMap(); + for (index, scope_data) in mir.visibility_scopes.iter().enumerate() { + if let Some(parent) = scope_data.parent_scope { + scope_tree.entry(parent) + .or_insert(vec![]) + .push(VisibilityScope::new(index)); + } else { + // Only the argument scope has no parent, because it's the root. + assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index()); + } + } + + write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?; + + write_mir_decls(mir, w) } fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) @@ -318,29 +317,7 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) } } -fn write_mir_decls(tcx: TyCtxt, mir: &Mir, w: &mut Write) - -> io::Result<()> -{ - // User variable types (including the user's name in a comment). - for (i, var) in mir.var_decls.iter().enumerate() { - let mut_str = if var.mutability == Mutability::Mut { - "mut " - } else { - "" - }; - - let indented_var = format!("{}let {}{:?}: {};", - INDENT, - mut_str, - Lvalue::Var(i as u32), - var.ty); - writeln!(w, "{0:1$} // \"{2}\" in {3}", - indented_var, - ALIGN, - var.name, - comment(tcx, var.scope, var.span))?; - } - +fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> { // Compiler-introduced temporary types. for (i, temp) in mir.temp_decls.iter().enumerate() { writeln!(w, "{}let mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty)?; diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index bcdd62c189972..987f12ab71b4a 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -11,11 +11,9 @@ use rustc::ty::TyCtxt; use rustc::mir::repr::*; use rustc::mir::transform::{MirPass, MirSource, Pass}; - +use rustc::mir::traversal; use pretty; -use traversal; - pub struct AddCallGuards; /** @@ -66,15 +64,14 @@ impl<'tcx> MirPass<'tcx> for AddCallGuards { destination: Some((_, ref mut destination)), cleanup: Some(_), .. - }, span, scope + }, source_info }) if pred_count[destination.index()] > 1 => { // It's a critical edge, break it let call_guard = BasicBlockData { statements: vec![], is_cleanup: data.is_cleanup, terminator: Some(Terminator { - span: span, - scope: scope, + source_info: source_info, kind: TerminatorKind::Goto { target: *destination } }) }; diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index d81c4e2dfb68e..985bc9ac2d8d7 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -24,11 +24,11 @@ use rustc::mir::repr::*; use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor}; +use rustc::mir::traversal::ReversePostorder; use rustc::ty::{self, TyCtxt}; use syntax::codemap::Span; use build::Location; -use traversal::ReversePostorder; use std::mem; @@ -117,18 +117,16 @@ 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.span = statement.span; self.super_statement(bb, statement); self.location.statement_index += 1; } - fn visit_terminator(&mut self, bb: BasicBlock, terminator: &Terminator<'tcx>) { - self.span = terminator.span; - self.super_terminator(bb, terminator); - } - fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) { self.location.statement_index = 0; self.location.block = bb; @@ -167,8 +165,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { self.promoted.basic_blocks.push(BasicBlockData { statements: vec![], terminator: Some(Terminator { - span: self.promoted.span, - scope: ScopeId::new(0), + source_info: SourceInfo { + span: self.promoted.span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, kind: TerminatorKind::Return }), is_cleanup: false @@ -179,8 +179,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { fn assign(&mut self, dest: Lvalue<'tcx>, rvalue: Rvalue<'tcx>, span: Span) { let data = self.promoted.basic_blocks.last_mut().unwrap(); data.statements.push(Statement { - span: span, - scope: ScopeId::new(0), + source_info: SourceInfo { + span: span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, kind: StatementKind::Assign(dest, rvalue) }); } @@ -214,7 +216,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { // First, take the Rvalue or Call out of the source MIR, // or duplicate it, depending on keep_original. let (mut rvalue, mut call) = (None, None); - let span = if stmt_idx < no_stmts { + let source_info = if stmt_idx < no_stmts { let statement = &mut self.source[bb].statements[stmt_idx]; let StatementKind::Assign(_, ref mut rhs) = statement.kind; if self.keep_original { @@ -223,11 +225,11 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let unit = Rvalue::Aggregate(AggregateKind::Tuple, vec![]); rvalue = Some(mem::replace(rhs, unit)); } - statement.span + statement.source_info } else if self.keep_original { let terminator = self.source[bb].terminator().clone(); call = Some(terminator.kind); - terminator.span + terminator.source_info } else { let terminator = self.source[bb].terminator_mut(); let target = match terminator.kind { @@ -242,13 +244,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { dest.take().unwrap().1 } ref kind => { - span_bug!(terminator.span, "{:?} not promotable", kind); + span_bug!(terminator.source_info.span, "{:?} not promotable", kind); } }; call = Some(mem::replace(&mut terminator.kind, TerminatorKind::Goto { target: target })); - terminator.span + terminator.source_info }; // Then, recurse for components in the Rvalue or Call. @@ -266,7 +268,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { // Inject the Rvalue or Call into the promoted MIR. if stmt_idx < no_stmts { - self.assign(new_temp, rvalue.unwrap(), span); + self.assign(new_temp, rvalue.unwrap(), source_info.span); } else { let last = self.promoted.basic_blocks.len() - 1; let new_target = self.new_block(); @@ -278,7 +280,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { _ => bug!() } let terminator = &mut self.promoted.basic_blocks[last].terminator_mut(); - terminator.span = span; + terminator.source_info.span = source_info.span; terminator.kind = call; } @@ -346,7 +348,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, continue; } } - (statement.span, mir.lvalue_ty(tcx, dest).to_ty(tcx)) + (statement.source_info.span, mir.lvalue_ty(tcx, dest).to_ty(tcx)) } Candidate::ShuffleIndices(bb) => { let terminator = mir[bb].terminator(); @@ -355,11 +357,11 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, mir.operand_ty(tcx, &args[2]) } _ => { - span_bug!(terminator.span, + span_bug!(terminator.source_info.span, "expected simd_shuffleN call to promote"); } }; - (terminator.span, ty) + (terminator.source_info.span, ty) } }; @@ -367,7 +369,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, source: mir, promoted: Mir { basic_blocks: vec![], - scopes: vec![ScopeData { + visibility_scopes: vec![VisibilityScopeData { span: span, parent_scope: None }], diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index b9eec6ecd9c58..3fdf492611d46 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -25,6 +25,7 @@ use rustc::ty::cast::CastTy; use rustc::mir::repr::*; use rustc::mir::mir_map::MirMap; use rustc::mir::transform::{Pass, MirMapPass, MirSource}; +use rustc::mir::traversal::{self, ReversePostorder}; use rustc::mir::visit::{LvalueContext, Visitor}; use rustc::util::nodemap::DefIdMap; use syntax::abi::Abi; @@ -35,7 +36,6 @@ use std::collections::hash_map::Entry; use std::fmt; use build::Location; -use traversal::{self, ReversePostorder}; use super::promote_consts::{self, Candidate, TempState}; @@ -377,11 +377,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { let stmt_idx = location.statement_index; // Get the span for the initialization. - if stmt_idx < data.statements.len() { - self.span = data.statements[stmt_idx].span; + let source_info = if stmt_idx < data.statements.len() { + data.statements[stmt_idx].source_info } else { - self.span = data.terminator().span; - } + data.terminator().source_info + }; + self.span = source_info.span; // Treat this as a statement in the AST. self.statement_like(); @@ -508,6 +509,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } ProjectionElem::ConstantIndex {..} | + ProjectionElem::Subslice {..} | ProjectionElem::Downcast(..) => { this.not_const() } @@ -707,7 +709,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - Rvalue::Slice {..} | Rvalue::InlineAsm {..} => { self.not_const(); } @@ -830,7 +831,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Avoid a generic error for other uses of arguments. if self.qualif.intersects(Qualif::FN_ARGUMENT) { let decl = &self.mir.var_decls[index as usize]; - span_err!(self.tcx.sess, decl.span, E0022, + span_err!(self.tcx.sess, decl.source_info.span, E0022, "arguments of constant functions can only \ be immutable by-value bindings"); return; @@ -841,16 +842,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.assign(dest); } + 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.span = statement.span; 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.span = terminator.span; self.nest(|this| this.super_terminator(bb, terminator)); } diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index d008918026ab8..3a0055c564feb 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -13,13 +13,12 @@ use rustc::middle::const_val::ConstVal; use rustc::ty::TyCtxt; use rustc::mir::repr::*; use rustc::mir::transform::{MirPass, MirSource, Pass}; +use rustc::mir::traversal; use pretty; use std::mem; use super::remove_dead_blocks::RemoveDeadBlocks; -use traversal; - pub struct SimplifyCfg; impl SimplifyCfg { diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 019ed670d1f83..c38f1f1e6c0fa 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -203,6 +203,26 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { }) } } + ProjectionElem::Subslice { from, to } => { + LvalueTy::Ty { + ty: match base_ty.sty { + ty::TyArray(inner, size) => { + let min_size = (from as usize) + (to as usize); + if let Some(rest_size) = size.checked_sub(min_size) { + tcx.mk_array(inner, rest_size) + } else { + span_mirbug_and_err!( + self, lvalue, "taking too-small slice of {:?}", base_ty) + } + } + ty::TySlice(..) => base_ty, + _ => { + span_mirbug_and_err!( + self, lvalue, "slice of non-array {:?}", base_ty) + } + } + } + } ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty { ty::TyEnum(adt_def, substs) if adt_def == adt_def1 => { @@ -551,7 +571,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block: &BasicBlockData<'tcx>) { let is_cleanup = block.is_cleanup; - self.last_span = block.terminator().span; + self.last_span = block.terminator().source_info.span; match block.terminator().kind { TerminatorKind::Goto { target } => self.assert_iscleanup(mir, block, target, is_cleanup), @@ -617,8 +637,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { debug!("run_on_mir: {:?}", mir.span); for block in &mir.basic_blocks { for stmt in &block.statements { - if stmt.span != DUMMY_SP { - self.last_span = stmt.span; + if stmt.source_info.span != DUMMY_SP { + self.last_span = stmt.source_info.span; } self.check_stmt(mir, stmt); } diff --git a/src/librustc_plugin/Cargo.toml b/src/librustc_plugin/Cargo.toml index e9a32e53a9fe6..6acd1e76ff2c2 100644 --- a/src/librustc_plugin/Cargo.toml +++ b/src/librustc_plugin/Cargo.toml @@ -14,5 +14,4 @@ rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_metadata = { path = "../librustc_metadata" } -rustc_mir = { path = "../librustc_mir" } syntax = { path = "../libsyntax" } diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index 5fa29771c57fb..7ef628e8f9b16 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -70,7 +70,6 @@ extern crate rustc; extern crate rustc_back; extern crate rustc_metadata; -extern crate rustc_mir; pub use self::registry::Registry; diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 9a0580472b401..749ceda3db094 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -21,7 +21,6 @@ rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_incremental = { path = "../librustc_incremental" } rustc_llvm = { path = "../librustc_llvm" } -rustc_mir = { path = "../librustc_mir" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index 74e8daf97e387..913b0528b2e19 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -505,14 +505,16 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: MatchInput, mut e: F) -> Vec> where - F: FnMut(&[&'p hir::Pat]) -> Option>, + F: FnMut(&[(&'p hir::Pat, Option>)]) + -> Option>)>>, { debug!("enter_match(bcx={}, m={:?}, col={}, val={:?})", bcx.to_str(), m, col, val); let _indenter = indenter(); m.iter().filter_map(|br| { - e(&br.pats).map(|pats| { + let pats : Vec<_> = br.pats.iter().map(|p| (*p, None)).collect(); + e(&pats).map(|pats| { let this = br.pats[col]; let mut bound_ptrs = br.bound_ptrs.clone(); match this.node { @@ -530,7 +532,7 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, _ => {} } Match { - pats: pats, + pats: pats.into_iter().map(|p| p.0).collect(), data: br.data, bound_ptrs: bound_ptrs, pat_renaming_map: br.pat_renaming_map, @@ -550,7 +552,7 @@ fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Collect all of the matches that can match against anything. enter_match(bcx, m, col, val, |pats| { - match pats[col].node { + match pats[col].0.node { PatKind::Binding(..) | PatKind::Wild => { let mut r = pats[..col].to_vec(); r.extend_from_slice(&pats[col + 1..]); @@ -729,7 +731,14 @@ fn bind_subslice_pat(bcx: Block, let (base, len) = vec_datum.get_vec_base_and_len(bcx); let slice_begin = InBoundsGEP(bcx, base, &[C_uint(bcx.ccx(), offset_left)]); - let slice_len_offset = C_uint(bcx.ccx(), offset_left + offset_right); + let diff = offset_left + offset_right; + if let ty::TyArray(ty, n) = vec_ty_contents.sty { + let array_ty = bcx.tcx().mk_array(ty, n-diff); + let llty_array = type_of::type_of(bcx.ccx(), array_ty); + return PointerCast(bcx, slice_begin, llty_array.ptr_to()); + } + + let slice_len_offset = C_uint(bcx.ccx(), diff); let slice_len = Sub(bcx, len, slice_len_offset, DebugLoc::None); let slice_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReErased), bcx.tcx().mk_slice(unit_ty)); @@ -1205,7 +1214,12 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } Some(field_vals) } else if any_uniq_pat(m, col) || any_region_pat(m, col) { - Some(vec!(Load(bcx, val.val))) + let ptr = if type_is_fat_ptr(bcx.tcx(), left_ty) { + val.val + } else { + Load(bcx, val.val) + }; + Some(vec!(ptr)) } else { match left_ty.sty { ty::TyArray(_, n) => { diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index bba0edd5f0496..f75f973f68aab 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -16,7 +16,7 @@ use llvm; use llvm::debuginfo::{DIScope, DISubprogram}; use common::{CrateContext, FunctionContext}; use rustc::hir::pat_util; -use rustc::mir::repr::{Mir, ScopeId}; +use rustc::mir::repr::{Mir, VisibilityScope}; use rustc::util::nodemap::NodeMap; use libc::c_uint; @@ -71,7 +71,7 @@ pub fn create_scope_map(cx: &CrateContext, /// If debuginfo is disabled, the returned vector is empty. pub fn create_mir_scopes(fcx: &FunctionContext) -> Vec { let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn"); - let mut scopes = vec![ptr::null_mut(); mir.scopes.len()]; + let mut scopes = vec![ptr::null_mut(); mir.visibility_scopes.len()]; let fn_metadata = match fcx.debug_context { FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata, @@ -82,14 +82,14 @@ pub fn create_mir_scopes(fcx: &FunctionContext) -> Vec { }; // Find all the scopes with variables defined in them. - let mut has_variables = BitVector::new(mir.scopes.len()); + let mut has_variables = BitVector::new(mir.visibility_scopes.len()); for var in &mir.var_decls { - has_variables.insert(var.scope.index()); + has_variables.insert(var.source_info.scope.index()); } // Instantiate all scopes. - for idx in 0..mir.scopes.len() { - let scope = ScopeId::new(idx); + for idx in 0..mir.visibility_scopes.len() { + let scope = VisibilityScope::new(idx); make_mir_scope(fcx.ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes); } @@ -100,14 +100,14 @@ fn make_mir_scope(ccx: &CrateContext, mir: &Mir, has_variables: &BitVector, fn_metadata: DISubprogram, - scope: ScopeId, + scope: VisibilityScope, scopes: &mut [DIScope]) { let idx = scope.index(); if !scopes[idx].is_null() { return; } - let scope_data = &mir.scopes[scope]; + let scope_data = &mir.visibility_scopes[scope]; let parent_scope = if let Some(parent) = scope_data.parent_scope { make_mir_scope(ccx, mir, has_variables, fn_metadata, parent, scopes); scopes[parent.index()] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 0188a6d54de2d..8724945ed901b 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -48,7 +48,6 @@ extern crate rustc_back; extern crate rustc_data_structures; extern crate rustc_incremental; pub extern crate rustc_llvm as llvm; -extern crate rustc_mir; extern crate rustc_platform_intrinsics as intrinsics; extern crate serialize; extern crate rustc_const_math; diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 59143bc01bf7a..4476163a7f108 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -15,7 +15,7 @@ use rustc_data_structures::bitvec::BitVector; use rustc::mir::repr as mir; use rustc::mir::repr::TerminatorKind; use rustc::mir::visit::{Visitor, LvalueContext}; -use rustc_mir::traversal; +use rustc::mir::traversal; use common::{self, Block, BlockAndBuilder}; use super::rvalue; diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index b7aca4c8d7fed..8a33bbbeae5c5 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -108,8 +108,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let terminator = data.terminator(); debug!("trans_block: terminator: {:?}", terminator); - let debug_loc = DebugLoc::ScopeAt(self.scopes[terminator.scope.index()], - terminator.span); + let span = terminator.source_info.span; + let debug_loc = self.debug_loc(terminator.source_info); debug_loc.apply_to_bcx(&bcx); debug_loc.apply(bcx.fcx()); match terminator.kind { @@ -247,7 +247,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { bcx = panic_block.build(); // Get the location information. - let loc = bcx.sess().codemap().lookup_char_pos(terminator.span.lo); + let loc = bcx.sess().codemap().lookup_char_pos(span.lo); let filename = token::intern_and_get_ident(&loc.file.name); let filename = C_str_slice(bcx.ccx(), filename); let line = C_u32(bcx.ccx(), loc.line as u32); @@ -298,15 +298,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // is also constant, then we can produce a warning. if const_cond == Some(!expected) { if let Some(err) = const_err { - let _ = consts::const_err(bcx.ccx(), - terminator.span, + let _ = consts::const_err(bcx.ccx(), span, Err::<(), _>(err), consts::TrueConst::No); } } // Obtain the panic entry point. - let def_id = common::langcall(bcx.tcx(), Some(terminator.span), "", lang_item); + let def_id = common::langcall(bcx.tcx(), Some(span), "", lang_item); let callee = Callee::def(bcx.ccx(), def_id, bcx.ccx().empty_substs_for_def_id(def_id)); let llfn = callee.reify(bcx.ccx()).val; @@ -419,8 +418,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { if is_shuffle && idx == 2 { match *arg { mir::Operand::Consume(_) => { - span_bug!(terminator.span, - "shuffle indices must be constant"); + span_bug!(span, "shuffle indices must be constant"); } mir::Operand::Constant(ref constant) => { let val = self.trans_constant(&bcx, constant); @@ -779,9 +777,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } let dest = match *dest { mir::Lvalue::Temp(idx) => { - let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), dest); - let lvalue_ty = bcx.monomorphize(&lvalue_ty); - let ret_ty = lvalue_ty.to_ty(bcx.tcx()); + let ret_ty = self.lvalue_ty(dest); match self.temps[idx as usize] { TempRef::Lvalue(dest) => dest, TempRef::Operand(None) => { diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 0cfb14955fc3f..4aa6aadb2706e 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -281,12 +281,13 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { loop { let data = self.mir.basic_block_data(bb); for statement in &data.statements { + let span = statement.source_info.span; match statement.kind { mir::StatementKind::Assign(ref dest, ref rvalue) => { let ty = self.mir.lvalue_ty(tcx, dest); let ty = self.monomorphize(&ty).to_ty(tcx); - match self.const_rvalue(rvalue, ty, statement.span) { - Ok(value) => self.store(dest, value, statement.span), + match self.const_rvalue(rvalue, ty, span) { + Ok(value) => self.store(dest, value, span), Err(err) => if failure.is_ok() { failure = Err(err); } } } @@ -294,7 +295,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } let terminator = data.terminator(); - let span = terminator.span; + let span = terminator.source_info.span; bb = match terminator.kind { mir::TerminatorKind::Drop { target, .. } | // No dropping. mir::TerminatorKind::Goto { target } => target, diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index bc79482666c92..523dfef5a2409 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -20,13 +20,14 @@ use common::{self, BlockAndBuilder, CrateContext, C_uint, C_undef}; use consts; use machine; use type_of::type_of; +use type_of; use Disr; use std::ptr; use super::{MirContext, TempRef}; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct LvalueRef<'tcx> { /// Pointer to the contents of the lvalue pub llval: ValueRef, @@ -88,7 +89,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let fcx = bcx.fcx(); let ccx = bcx.ccx(); let tcx = bcx.tcx(); - match *lvalue { + let result = match *lvalue { mir::Lvalue::Var(index) => self.vars[index as usize], mir::Lvalue::Temp(index) => match self.temps[index as usize] { TempRef::Lvalue(lvalue) => @@ -98,8 +99,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { }, mir::Lvalue::Arg(index) => self.args[index as usize], mir::Lvalue::Static(def_id) => { - let const_ty = self.mir.lvalue_ty(tcx, lvalue); - LvalueRef::new_sized(consts::get_static(ccx, def_id).val, const_ty) + let const_ty = self.lvalue_ty(lvalue); + LvalueRef::new_sized(consts::get_static(ccx, def_id).val, + LvalueTy::from_ty(const_ty)) }, mir::Lvalue::ReturnPointer => { let llval = if !fcx.fn_ty.ret.is_ignore() { @@ -131,7 +133,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let zero = common::C_uint(bcx.ccx(), 0u64); bcx.inbounds_gep(tr_base.llval, &[zero, llindex]) }; - (element, ptr::null_mut()) + element }; let (llprojected, llextra) = match projection.elem { @@ -169,13 +171,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } mir::ProjectionElem::Index(ref index) => { let index = self.trans_operand(bcx, index); - project_index(self.prepare_index(bcx, index.immediate())) + (project_index(self.prepare_index(bcx, index.immediate())), ptr::null_mut()) } mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => { let lloffset = C_uint(bcx.ccx(), offset); - project_index(self.prepare_index(bcx, lloffset)) + (project_index(lloffset), ptr::null_mut()) } mir::ProjectionElem::ConstantIndex { offset, from_end: true, @@ -183,7 +185,30 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let lloffset = C_uint(bcx.ccx(), offset); let lllen = tr_base.len(bcx.ccx()); let llindex = bcx.sub(lllen, lloffset); - project_index(self.prepare_index(bcx, llindex)) + (project_index(llindex), ptr::null_mut()) + } + mir::ProjectionElem::Subslice { from, to } => { + let llindex = C_uint(bcx.ccx(), from); + let llbase = project_index(llindex); + + let base_ty = tr_base.ty.to_ty(bcx.tcx()); + match base_ty.sty { + ty::TyArray(..) => { + // must cast the lvalue pointer type to the new + // array type (*[%_; new_len]). + let base_ty = self.lvalue_ty(lvalue); + let llbasety = type_of::type_of(bcx.ccx(), base_ty).ptr_to(); + let llbase = bcx.pointercast(llbase, llbasety); + (llbase, ptr::null_mut()) + } + ty::TySlice(..) => { + assert!(tr_base.llextra != ptr::null_mut()); + let lllen = bcx.sub(tr_base.llextra, + C_uint(bcx.ccx(), from+to)); + (llbase, lllen) + } + _ => bug!("unexpected type {:?} in Subslice", base_ty) + } } mir::ProjectionElem::Downcast(..) => { (tr_base.llval, tr_base.llextra) @@ -195,7 +220,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { ty: projected_ty, } } - } + }; + debug!("trans_lvalue(lvalue={:?}) => {:?}", lvalue, result); + result } // Perform an action using the given Lvalue. @@ -210,27 +237,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { match self.temps[idx as usize] { TempRef::Lvalue(lvalue) => f(self, lvalue), TempRef::Operand(None) => { - let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), lvalue); - let lvalue_ty = bcx.monomorphize(&lvalue_ty); + let lvalue_ty = self.lvalue_ty(lvalue); let lvalue = LvalueRef::alloca(bcx, - lvalue_ty.to_ty(bcx.tcx()), + lvalue_ty, "lvalue_temp"); let ret = f(self, lvalue); - let op = self.trans_load(bcx, lvalue.llval, lvalue_ty.to_ty(bcx.tcx())); + let op = self.trans_load(bcx, lvalue.llval, lvalue_ty); self.temps[idx as usize] = TempRef::Operand(Some(op)); ret } TempRef::Operand(Some(_)) => { - let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), lvalue); - let lvalue_ty = bcx.monomorphize(&lvalue_ty); - // See comments in TempRef::new_operand as to why // we always have Some in a ZST TempRef::Operand. - let ty = lvalue_ty.to_ty(bcx.tcx()); + let ty = self.lvalue_ty(lvalue); if common::type_is_zero_size(bcx.ccx(), ty) { // Pass an undef pointer as no stores can actually occur. let llptr = C_undef(type_of(bcx.ccx(), ty).ptr_to()); - f(self, LvalueRef::new_sized(llptr, lvalue_ty)) + f(self, LvalueRef::new_sized(llptr, LvalueTy::from_ty(ty))) } else { bug!("Lvalue temp already set"); } @@ -264,4 +287,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { llindex } } + + pub fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> { + let tcx = self.fcx.ccx.tcx(); + let lvalue_ty = self.mir.lvalue_ty(tcx, lvalue); + self.fcx.monomorphize(&lvalue_ty.to_ty(tcx)) + } } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index d1206550b13d6..cd2060653b58e 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -34,7 +34,7 @@ use rustc_data_structures::bitvec::BitVector; pub use self::constant::trans_static_initializer; use self::lvalue::{LvalueRef, get_dataptr, get_meta}; -use rustc_mir::traversal; +use rustc::mir::traversal; use self::operand::{OperandRef, OperandValue}; @@ -112,6 +112,12 @@ pub struct MirContext<'bcx, 'tcx:'bcx> { scopes: Vec } +impl<'blk, 'tcx> MirContext<'blk, 'tcx> { + pub fn debug_loc(&self, source_info: mir::SourceInfo) -> DebugLoc { + DebugLoc::ScopeAt(self.scopes[source_info.scope.index()], source_info.span) + } +} + enum TempRef<'tcx> { Lvalue(LvalueRef<'tcx>), Operand(Option>), @@ -161,12 +167,12 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { .map(|(mty, decl)| { let lvalue = LvalueRef::alloca(&bcx, mty, &decl.name.as_str()); - let scope = scopes[decl.scope.index()]; + let scope = scopes[decl.source_info.scope.index()]; if !scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo { bcx.with_block(|bcx| { declare_local(bcx, decl.name, mty, scope, VariableAccess::DirectVariable { alloca: lvalue.llval }, - VariableKind::LocalVariable, decl.span); + VariableKind::LocalVariable, decl.source_info.span); }); } @@ -266,16 +272,13 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, let mut idx = 0; let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize; - // Get the argument scope assuming ScopeId(0) has no parent. - let arg_scope = mir.scopes.get(0).and_then(|data| { - let scope = scopes[0]; - if data.parent_scope.is_none() && !scope.is_null() && - bcx.sess().opts.debuginfo == FullDebugInfo { - Some(scope) - } else { - None - } - }); + // Get the argument scope, if it exists and if we need it. + let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE.index()]; + let arg_scope = if !arg_scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo { + Some(arg_scope) + } else { + None + }; mir.arg_decls.iter().enumerate().map(|(arg_index, arg_decl)| { let arg_ty = bcx.monomorphize(&arg_decl.ty); diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 6779498fe2c6e..09b07c1440ec5 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -29,7 +29,7 @@ use Disr; use super::MirContext; use super::constant::const_scalar_checked_binop; use super::operand::{OperandRef, OperandValue}; -use super::lvalue::{LvalueRef, get_dataptr, get_meta}; +use super::lvalue::{LvalueRef, get_dataptr}; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_rvalue(&mut self, @@ -170,26 +170,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { bcx } - mir::Rvalue::Slice { ref input, from_start, from_end } => { - let ccx = bcx.ccx(); - let input = self.trans_lvalue(&bcx, input); - let ty = input.ty.to_ty(bcx.tcx()); - let (llbase1, lllen) = match ty.sty { - ty::TyArray(_, n) => { - (bcx.gepi(input.llval, &[0, from_start]), C_uint(ccx, n)) - } - ty::TySlice(_) | ty::TyStr => { - (bcx.gepi(input.llval, &[from_start]), input.llextra) - } - _ => bug!("cannot slice {}", ty) - }; - let adj = C_uint(ccx, from_start + from_end); - let lllen1 = bcx.sub(lllen, adj); - bcx.store(llbase1, get_dataptr(&bcx, dest.llval)); - bcx.store(lllen1, get_meta(&bcx, dest.llval)); - bcx - } - mir::Rvalue::InlineAsm { ref asm, ref outputs, ref inputs } => { let outputs = outputs.iter().map(|output| { let lvalue = self.trans_lvalue(&bcx, output); @@ -498,7 +478,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) | - mir::Rvalue::Slice { .. } | mir::Rvalue::InlineAsm { .. } => { bug!("cannot generate operand from rvalue {:?}", rvalue); @@ -652,7 +631,6 @@ pub fn rvalue_creates_operand<'bcx, 'tcx>(_mir: &mir::Mir<'tcx>, true, mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) | - mir::Rvalue::Slice { .. } | mir::Rvalue::InlineAsm { .. } => false, } diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs index c9a4e540fa06b..63472d582330f 100644 --- a/src/librustc_trans/mir/statement.rs +++ b/src/librustc_trans/mir/statement.rs @@ -10,7 +10,6 @@ use rustc::mir::repr as mir; use common::{self, BlockAndBuilder}; -use debuginfo::DebugLoc; use super::MirContext; use super::TempRef; @@ -22,8 +21,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { -> BlockAndBuilder<'bcx, 'tcx> { debug!("trans_statement(statement={:?})", statement); - let debug_loc = DebugLoc::ScopeAt(self.scopes[statement.scope.index()], - statement.span); + let debug_loc = self.debug_loc(statement.source_info); debug_loc.apply_to_bcx(&bcx); debug_loc.apply(bcx.fcx()); match statement.kind { @@ -42,11 +40,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { bcx } TempRef::Operand(Some(_)) => { - let ty = self.mir.lvalue_ty(bcx.tcx(), lvalue); - let ty = bcx.monomorphize(&ty.to_ty(bcx.tcx())); + let ty = self.lvalue_ty(lvalue); if !common::type_is_zero_size(bcx.ccx(), ty) { - span_bug!(statement.span, + span_bug!(statement.source_info.span, "operand {:?} already assigned", rvalue); } else { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 99b443e292491..0430585fe6d0b 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -19,8 +19,8 @@ use lint; use util::nodemap::FnvHashMap; use session::Session; -use std::cmp; use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::cmp; use std::ops::Deref; use syntax::ast; use syntax::codemap::{Span, Spanned}; @@ -323,44 +323,53 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { } PatKind::Vec(ref before, ref slice, ref after) => { let expected_ty = self.structurally_resolved_type(pat.span, expected); - let inner_ty = self.next_ty_var(); - let pat_ty = match expected_ty.sty { - ty::TyArray(_, size) => tcx.mk_array(inner_ty, { + let (inner_ty, slice_ty) = match expected_ty.sty { + ty::TyArray(inner_ty, size) => { let min_len = before.len() + after.len(); - match *slice { - Some(_) => cmp::max(min_len, size), - None => min_len + if slice.is_none() { + if min_len != size { + span_err!(tcx.sess, pat.span, E0527, + "pattern requires {} elements but array has {}", + min_len, size); + } + (inner_ty, tcx.types.err) + } else if let Some(rest) = size.checked_sub(min_len) { + (inner_ty, tcx.mk_array(inner_ty, rest)) + } else { + span_err!(tcx.sess, pat.span, E0528, + "pattern requires at least {} elements but array has {}", + min_len, size); + (inner_ty, tcx.types.err) } - }), + } + ty::TySlice(inner_ty) => (inner_ty, expected_ty), _ => { - let region = self.next_region_var(infer::PatternRegion(pat.span)); - tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut { - ty: tcx.mk_slice(inner_ty), - mutbl: expected_ty.builtin_deref(true, ty::NoPreference) - .map_or(hir::MutImmutable, |mt| mt.mutbl) - }) + if !expected_ty.references_error() { + let mut err = struct_span_err!( + tcx.sess, pat.span, E0529, + "expected an array or slice, found `{}`", + expected_ty); + if let ty::TyRef(_, ty::TypeAndMut { mutbl: _, ty }) = expected_ty.sty { + match ty.sty { + ty::TyArray(..) | ty::TySlice(..) => { + err.help("the semantics of slice patterns changed \ + recently; see issue #23121"); + } + _ => {} + } + } + err.emit(); + } + (tcx.types.err, tcx.types.err) } }; - self.write_ty(pat.id, pat_ty); - - // `demand::subtype` would be good enough, but using - // `eqtype` turns out to be equally general. See (*) - // below for details. - self.demand_eqtype(pat.span, expected, pat_ty); + self.write_ty(pat.id, expected_ty); for elt in before { self.check_pat(&elt, inner_ty); } if let Some(ref slice) = *slice { - let region = self.next_region_var(infer::PatternRegion(pat.span)); - let mutbl = expected_ty.builtin_deref(true, ty::NoPreference) - .map_or(hir::MutImmutable, |mt| mt.mutbl); - - let slice_ty = tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut { - ty: tcx.mk_slice(inner_ty), - mutbl: mutbl - }); self.check_pat(&slice, slice_ty); } for elt in after { @@ -369,7 +378,6 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { } } - // (*) In most of the cases above (literals and constants being // the exception), we relate types using strict equality, evewn // though subtyping would be sufficient. There are a few reasons diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index fd1b60551734c..a8cb21126c079 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1157,25 +1157,13 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat); - let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| { + let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| { match sub_pat.node { // `ref x` pattern PatKind::Binding(hir::BindByRef(mutbl), _, _) => { self.link_region_from_node_type(sub_pat.span, sub_pat.id, mutbl, sub_cmt); } - - // `[_, ..slice, _]` pattern - PatKind::Vec(_, Some(ref slice_pat), _) => { - match mc.cat_slice_pattern(sub_cmt, &slice_pat) { - Ok((slice_cmt, slice_mutbl, slice_r)) => { - self.link_region(sub_pat.span, &slice_r, - ty::BorrowKind::from_mutbl(slice_mutbl), - slice_cmt); - } - Err(()) => {} - } - } _ => {} } }); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 67a082ee52066..86717da24c54f 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4139,5 +4139,8 @@ register_diagnostics! { // type `{}` was overridden E0436, // functional record update requires a struct E0513, // no type for local variable .. - E0521 // redundant default implementations of trait + E0521, // redundant default implementations of trait + E0527, // expected {} elements, found {} + E0528, // expected at least {} elements, found {} + E0529, // slice pattern expects array or slice, not `{}` } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f5d54123f37b5..f5ca125aca91b 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -22,6 +22,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::print as pprust; use rustc::ty::{self, TyCtxt}; use rustc::ty::subst; +use rustc::util::common::slice_pat; use rustc_const_eval::lookup_const_by_id; @@ -197,10 +198,10 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, let variant = tcx.lookup_adt_def(did).struct_variant(); clean::Struct { - struct_type: match &*variant.fields { - [] => doctree::Unit, - [_] if variant.kind == ty::VariantKind::Tuple => doctree::Newtype, - [..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple, + struct_type: match slice_pat(&&*variant.fields) { + &[] => doctree::Unit, + &[_] if variant.kind == ty::VariantKind::Tuple => doctree::Newtype, + &[..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple, _ => doctree::Plain, }, generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 92401a5c55ffd..760e84622cfe5 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -20,6 +20,7 @@ use std::iter::repeat; use rustc::middle::cstore::LOCAL_CRATE; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::util::common::slice_pat; use syntax::abi::Abi; use rustc::hir; @@ -474,9 +475,9 @@ impl fmt::Display for clean::Type { decl.decl) } clean::Tuple(ref typs) => { - match &**typs { - [] => primitive_link(f, clean::PrimitiveTuple, "()"), - [ref one] => { + match slice_pat(&&**typs) { + &[] => primitive_link(f, clean::PrimitiveTuple, "()"), + &[ref one] => { primitive_link(f, clean::PrimitiveTuple, "(")?; write!(f, "{},", one)?; primitive_link(f, clean::PrimitiveTuple, ")") diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7114d47e6e890..135ea8a5e7cb4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -467,3 +467,15 @@ pub mod __rand { // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. include!("primitive_docs.rs"); + +// FIXME(stage0): remove this after a snapshot +// HACK: this is needed because the interpretation of slice +// patterns changed between stage0 and now. +#[cfg(stage0)] +fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'a &'b [T] { + t +} +#[cfg(not(stage0))] +fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'b [T] { + *t +} diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index ffd33f8518f68..02506e7c2f3d9 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -265,15 +265,18 @@ mod tests { // Ensure the borrowchecker works match queue.peek() { - Some(vec) => match &**vec { - // Note that `pop` is not allowed here due to borrow - [1] => {} - _ => return + Some(vec) => { + assert_eq!(&*vec, &[1]); }, None => unreachable!() } - queue.pop(); + match queue.pop() { + Some(vec) => { + assert_eq!(&*vec, &[1]); + }, + None => unreachable!() + } } } diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index 55e485e5811ac..d705b8986d0b1 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -566,8 +566,8 @@ impl Wtf8 { if len < 3 { return None } - match &self.bytes[(len - 3)..] { - [0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)), + match ::slice_pat(&&self.bytes[(len - 3)..]) { + &[0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)), _ => None } } @@ -578,8 +578,8 @@ impl Wtf8 { if len < 3 { return None } - match &self.bytes[..3] { - [0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)), + match ::slice_pat(&&self.bytes[..3]) { + &[0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)), _ => None } } diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 3cd45afaf0148..c243e890526f7 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -117,10 +117,10 @@ impl Drop for FindNextFileHandle { impl DirEntry { fn new(root: &Arc, wfd: &c::WIN32_FIND_DATAW) -> Option { - match &wfd.cFileName[0..3] { + match ::slice_pat(&&wfd.cFileName[0..3]) { // check for '.' and '..' - [46, 0, ..] | - [46, 46, 0, ..] => return None, + &[46, 0, ..] | + &[46, 46, 0, ..] => return None, _ => {} } diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 931f90a239421..50d9f61e2c160 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -238,7 +238,6 @@ dependencies = [ "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_metadata 0.0.0", - "rustc_mir 0.0.0", "syntax 0.0.0", ] @@ -285,7 +284,6 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_incremental 0.0.0", "rustc_llvm 0.0.0", - "rustc_mir 0.0.0", "rustc_platform_intrinsics 0.0.0", "serialize 0.0.0", "syntax 0.0.0", diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs index 15771295743c1..f595d9d81cc6e 100644 --- a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs +++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs @@ -24,14 +24,14 @@ pub fn main() { Foo { string: "baz".to_string() } ); let x: &[Foo] = &x; - match x { - [_, tail..] => { + match *x { + [_, ref tail..] => { match tail { - [Foo { string: a }, + &[Foo { string: a }, //~^ ERROR cannot move out of borrowed content //~| cannot move out //~| to prevent move - Foo { string: b }] => { + Foo { string: b }] => { //~^ NOTE and here } _ => { diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs index 98052ad31a7ef..63e80b90ac81e 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs @@ -15,7 +15,7 @@ fn a<'a>() -> &'a [isize] { let vec = vec!(1, 2, 3, 4); let vec: &[isize] = &vec; //~ ERROR does not live long enough let tail = match vec { - [_, tail..] => tail, + &[_, ref tail..] => tail, _ => panic!("a") }; tail @@ -25,7 +25,7 @@ fn b<'a>() -> &'a [isize] { let vec = vec!(1, 2, 3, 4); let vec: &[isize] = &vec; //~ ERROR does not live long enough let init = match vec { - [init.., _] => init, + &[ref init.., _] => init, _ => panic!("b") }; init @@ -35,7 +35,7 @@ fn c<'a>() -> &'a [isize] { let vec = vec!(1, 2, 3, 4); let vec: &[isize] = &vec; //~ ERROR does not live long enough let slice = match vec { - [_, slice.., _] => slice, + &[_, ref slice.., _] => slice, _ => panic!("c") }; slice diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs index db635893c81b9..9dfd4d7792843 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs @@ -14,7 +14,7 @@ fn a() { let mut v = vec!(1, 2, 3); let vb: &mut [isize] = &mut v; match vb { - [_a, tail..] => { + &mut [_a, ref tail..] => { v.push(tail[0] + tail[1]); //~ ERROR cannot borrow } _ => {} diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-move-tail.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-move-tail.rs index 97dcaeb0bf1a3..fddb9838c44b5 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-move-tail.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-move-tail.rs @@ -13,7 +13,7 @@ fn main() { let mut a = [1, 2, 3, 4]; let t = match a { - [1, 2, tail..] => tail, + [1, 2, ref tail..] => tail, _ => unreachable!() }; println!("t[0]: {}", t[0]); diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs index eec6c8473eb3d..d89b4100789f9 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs @@ -28,7 +28,7 @@ fn b() { let mut vec = vec!(box 1, box 2, box 3); let vec: &mut [Box] = &mut vec; match vec { - [_b..] => { + &mut [ref _b..] => { //~^ borrow of `vec[..]` occurs here vec[0] = box 4; //~ ERROR cannot assign //~^ assignment to borrowed `vec[..]` occurs here @@ -40,10 +40,11 @@ fn c() { let mut vec = vec!(box 1, box 2, box 3); let vec: &mut [Box] = &mut vec; match vec { - [_a, //~ ERROR cannot move out - //~| cannot move out - //~| to prevent move - _b..] => { + &mut [_a, //~ ERROR cannot move out of borrowed content + //~| cannot move out + //~| to prevent move + .. + ] => { // Note: `_a` is *moved* here, but `b` is borrowing, // hence illegal. // @@ -61,7 +62,7 @@ fn d() { let mut vec = vec!(box 1, box 2, box 3); let vec: &mut [Box] = &mut vec; match vec { - [_a.., //~ ERROR cannot move out + &mut [ //~ ERROR cannot move out //~^ cannot move out _b] => {} //~ NOTE to prevent move _ => {} @@ -75,7 +76,7 @@ fn e() { let mut vec = vec!(box 1, box 2, box 3); let vec: &mut [Box] = &mut vec; match vec { - [_a, _b, _c] => {} //~ ERROR cannot move out + &mut [_a, _b, _c] => {} //~ ERROR cannot move out //~| cannot move out //~| NOTE to prevent move //~| NOTE and here diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs index 82b3490d7d7e1..a849e4e2faf3b 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs @@ -14,7 +14,7 @@ fn a<'a>() -> &'a isize { let vec = vec!(1, 2, 3, 4); let vec: &[isize] = &vec; //~ ERROR `vec` does not live long enough let tail = match vec { - [_a, tail..] => &tail[0], + &[_a, ref tail..] => &tail[0], _ => panic!("foo") }; tail diff --git a/src/test/compile-fail/issue-12369.rs b/src/test/compile-fail/issue-12369.rs index 1333bfac64ee8..978d6f59b2df4 100644 --- a/src/test/compile-fail/issue-12369.rs +++ b/src/test/compile-fail/issue-12369.rs @@ -13,9 +13,9 @@ fn main() { let sl = vec![1,2,3]; let v: isize = match &*sl { - [] => 0, - [a,b,c] => 3, - [a, rest..] => a, - [10,a, rest..] => 10 //~ ERROR: unreachable pattern + &[] => 0, + &[a,b,c] => 3, + &[a, ref rest..] => a, + &[10,a, ref rest..] => 10 //~ ERROR: unreachable pattern }; } diff --git a/src/test/compile-fail/issue-12567.rs b/src/test/compile-fail/issue-12567.rs index 1580ec00f94b0..32a6ea4f062cb 100644 --- a/src/test/compile-fail/issue-12567.rs +++ b/src/test/compile-fail/issue-12567.rs @@ -12,13 +12,15 @@ fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) { match (l1, l2) { - ([], []) => println!("both empty"), - ([], [hd, tl..]) | ([hd, tl..], []) => println!("one empty"), - //~^ ERROR: cannot move out of borrowed content + (&[], &[]) => println!("both empty"), + (&[], &[hd, ..]) | (&[hd, ..], &[]) + => println!("one empty"), //~^^ ERROR: cannot move out of borrowed content - ([hd1, tl1..], [hd2, tl2..]) => println!("both nonempty"), - //~^ ERROR: cannot move out of borrowed content + //~^^^ ERROR: cannot move out of borrowed content + (&[hd1, ..], &[hd2, ..]) + => println!("both nonempty"), //~^^ ERROR: cannot move out of borrowed content + //~^^^ ERROR: cannot move out of borrowed content } } diff --git a/src/test/compile-fail/issue-13482-2.rs b/src/test/compile-fail/issue-13482-2.rs index fe03373a45d9f..6885c8d94c6b4 100644 --- a/src/test/compile-fail/issue-13482-2.rs +++ b/src/test/compile-fail/issue-13482-2.rs @@ -15,11 +15,7 @@ fn main() { let x = [1,2]; let y = match x { - [] => None, -//~^ ERROR mismatched types -//~| expected type `[_#1i; 2]` -//~| found type `[_#7t; 0]` -//~| expected an array with a fixed size of 2 elements, found one with 0 elements + [] => None, //~ ERROR pattern requires 0 elements but array has 2 [a,_] => Some(a) }; } diff --git a/src/test/compile-fail/issue-13482.rs b/src/test/compile-fail/issue-13482.rs index 7ed7f5898b1b7..82e82df31861f 100644 --- a/src/test/compile-fail/issue-13482.rs +++ b/src/test/compile-fail/issue-13482.rs @@ -13,11 +13,7 @@ fn main() { let x = [1,2]; let y = match x { - [] => None, - //~^ ERROR mismatched types - //~| expected type `[_; 2]` - //~| found type `[_; 0]` - //~| expected an array with a fixed size of 2 elements + [] => None, //~ ERROR pattern requires 0 elements but array has 2 [a,_] => Some(a) }; } diff --git a/src/test/compile-fail/issue-15381.rs b/src/test/compile-fail/issue-15381.rs index ec29a84f44e4b..d0964d2aabea7 100644 --- a/src/test/compile-fail/issue-15381.rs +++ b/src/test/compile-fail/issue-15381.rs @@ -13,8 +13,8 @@ fn main() { let values: Vec = vec![1,2,3,4,5,6,7,8]; - for [x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) { - //~^ ERROR refutable pattern in `for` loop binding: `[]` not covered + for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) { + //~^ ERROR refutable pattern in `for` loop binding: `&[]` not covered println!("y={}", y); } } diff --git a/src/test/compile-fail/issue-30240.rs b/src/test/compile-fail/issue-30240.rs new file mode 100644 index 0000000000000..9b105e7ec159d --- /dev/null +++ b/src/test/compile-fail/issue-30240.rs @@ -0,0 +1,21 @@ +// 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. + +fn main() { + match "world" { //~ ERROR non-exhaustive patterns: `&_` + "hello" => {} + } + + match "world" { //~ ERROR non-exhaustive patterns: `&_` + ref _x if false => {} + "hello" => {} + "hello" => {} //~ ERROR unreachable pattern + } +} diff --git a/src/test/compile-fail/match-vec-mismatch-2.rs b/src/test/compile-fail/match-vec-mismatch-2.rs index 2831499c73d87..375d855d1fd31 100644 --- a/src/test/compile-fail/match-vec-mismatch-2.rs +++ b/src/test/compile-fail/match-vec-mismatch-2.rs @@ -13,9 +13,6 @@ fn main() { match () { [()] => { } - //~^ ERROR mismatched types - //~| expected type `()` - //~| found type `&[_]` - //~| expected (), found &-ptr + //~^ ERROR expected an array or slice, found `()` } } diff --git a/src/test/compile-fail/match-vec-mismatch.rs b/src/test/compile-fail/match-vec-mismatch.rs index ef75213d34b85..3ac4958e7db0f 100644 --- a/src/test/compile-fail/match-vec-mismatch.rs +++ b/src/test/compile-fail/match-vec-mismatch.rs @@ -12,7 +12,36 @@ fn main() { match "foo".to_string() { - ['f', 'o', ..] => {} //~ ERROR mismatched types + ['f', 'o', ..] => {} + //~^ ERROR expected an array or slice, found `std::string::String` _ => { } - } + }; + + match &[0, 1, 2] { + [..] => {} //~ ERROR expected an array or slice, found `&[_; 3]` + }; + + match &[0, 1, 2] { + &[..] => {} // ok + }; + + match [0, 1, 2] { + [0] => {}, //~ ERROR pattern requires + + [0, 1, x..] => { + let a: [_; 1] = x; + } + [0, 1, 2, 3, x..] => {} //~ ERROR pattern requires + }; + + match does_not_exist { //~ ERROR unresolved name + [] => {} + }; +} + +fn another_fn_to_avoid_suppression() { + match Default::default() + { + [] => {} //~ ERROR the type of this value + }; } diff --git a/src/test/compile-fail/match-vec-unreachable.rs b/src/test/compile-fail/match-vec-unreachable.rs index 48b70b4bda08e..57e3a58b5660e 100644 --- a/src/test/compile-fail/match-vec-unreachable.rs +++ b/src/test/compile-fail/match-vec-unreachable.rs @@ -13,7 +13,7 @@ fn main() { let x: Vec<(isize, isize)> = Vec::new(); let x: &[(isize, isize)] = &x; - match x { + match *x { [a, (2, 3), _] => (), [(1, 2), (2, 3), b] => (), //~ ERROR unreachable pattern _ => () @@ -23,7 +23,7 @@ fn main() { "bar".to_string(), "baz".to_string()]; let x: &[String] = &x; - match x { + match *x { [a, _, _, ..] => { println!("{}", a); } [_, _, _, _, _] => { } //~ ERROR unreachable pattern _ => { } @@ -31,8 +31,8 @@ fn main() { let x: Vec = vec!('a', 'b', 'c'); let x: &[char] = &x; - match x { - ['a', 'b', 'c', _tail..] => {} + match *x { + ['a', 'b', 'c', ref _tail..] => {} ['a', 'b', 'c'] => {} //~ ERROR unreachable pattern _ => {} } diff --git a/src/test/compile-fail/non-exhaustive-match-nested.rs b/src/test/compile-fail/non-exhaustive-match-nested.rs index ad2b8c400e576..1d524217a12a2 100644 --- a/src/test/compile-fail/non-exhaustive-match-nested.rs +++ b/src/test/compile-fail/non-exhaustive-match-nested.rs @@ -14,11 +14,11 @@ enum t { a(u), b } enum u { c, d } fn match_nested_vecs<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str { - match (l1, l2) { //~ ERROR non-exhaustive patterns: `(Some([]), Err(_))` not covered - (Some([]), Ok([])) => "Some(empty), Ok(empty)", - (Some([_, ..]), Ok(_)) | (Some([_, ..]), Err(())) => "Some(non-empty), any", - (None, Ok([])) | (None, Err(())) | (None, Ok([_])) => "None, Ok(less than one element)", - (None, Ok([_, _, ..])) => "None, Ok(at least two elements)" + match (l1, l2) { //~ ERROR non-exhaustive patterns: `(Some(&[]), Err(_))` not covered + (Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)", + (Some(&[_, ..]), Ok(_)) | (Some(&[_, ..]), Err(())) => "Some(non-empty), any", + (None, Ok(&[])) | (None, Err(())) | (None, Ok(&[_])) => "None, Ok(less than one element)", + (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)" } } diff --git a/src/test/compile-fail/non-exhaustive-match.rs b/src/test/compile-fail/non-exhaustive-match.rs index b9749c2696e32..017baacc9d329 100644 --- a/src/test/compile-fail/non-exhaustive-match.rs +++ b/src/test/compile-fail/non-exhaustive-match.rs @@ -39,20 +39,20 @@ fn main() { } let vec = vec!(Some(42), None, Some(21)); let vec: &[Option] = &vec; - match vec { //~ ERROR non-exhaustive patterns: `[]` not covered - [Some(..), None, tail..] => {} - [Some(..), Some(..), tail..] => {} + match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered + [Some(..), None, ref tail..] => {} + [Some(..), Some(..), ref tail..] => {} [None] => {} } let vec = vec!(1); let vec: &[isize] = &vec; - match vec { - [_, tail..] => (), + match *vec { + [_, ref tail..] => (), [] => () } let vec = vec!(0.5f32); let vec: &[f32] = &vec; - match vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered + match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered [0.1, 0.2, 0.3] => (), [0.1, 0.2] => (), [0.1] => (), @@ -60,11 +60,11 @@ fn main() { } let vec = vec!(Some(42), None, Some(21)); let vec: &[Option] = &vec; - match vec { - [Some(..), None, tail..] => {} - [Some(..), Some(..), tail..] => {} - [None, None, tail..] => {} - [None, Some(..), tail..] => {} + match *vec { + [Some(..), None, ref tail..] => {} + [Some(..), Some(..), ref tail..] => {} + [None, None, ref tail..] => {} + [None, Some(..), ref tail..] => {} [Some(_)] => {} [None] => {} [] => {} diff --git a/src/test/compile-fail/non-exhaustive-pattern-witness.rs b/src/test/compile-fail/non-exhaustive-pattern-witness.rs index b986878f78396..0b12a9acbcb9e 100644 --- a/src/test/compile-fail/non-exhaustive-pattern-witness.rs +++ b/src/test/compile-fail/non-exhaustive-pattern-witness.rs @@ -80,7 +80,7 @@ enum Enum { fn vectors_with_nested_enums() { let x: &'static [Enum] = &[Enum::First, Enum::Second(false)]; - match x { + match *x { //~^ ERROR non-exhaustive patterns: `[Second(true), Second(false)]` not covered [] => (), [_] => (), @@ -88,7 +88,7 @@ fn vectors_with_nested_enums() { [Enum::Second(true), Enum::First] => (), [Enum::Second(true), Enum::Second(true)] => (), [Enum::Second(false), _] => (), - [_, _, tail.., _] => () + [_, _, ref tail.., _] => () } } diff --git a/src/test/compile-fail/pat-slice-old-style.rs b/src/test/compile-fail/pat-slice-old-style.rs new file mode 100644 index 0000000000000..ccb25d859acba --- /dev/null +++ b/src/test/compile-fail/pat-slice-old-style.rs @@ -0,0 +1,22 @@ +// 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. + +#![feature(slice_patterns)] + +fn slice_pat(x: &[u8]) { + // OLD! + match x { + [a, b..] => {} + //~^ ERROR expected an array or slice, found `&[u8]` + //~| HELP the semantics of slice patterns changed recently; see issue #23121 + } +} + +fn main() {} diff --git a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs index f0ecda9299370..b5b6ca7572703 100644 --- a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs +++ b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs @@ -247,11 +247,10 @@ // lldb-command:continue #![allow(dead_code, unused_assignments, unused_variables)] -#![feature(omit_gdb_pretty_printer_section, rustc_attrs)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[no_stack_check] -#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn immediate_args(a: isize, b: bool, c: f64) { println!(""); } @@ -268,51 +267,43 @@ struct BigStruct { } #[no_stack_check] -#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn non_immediate_args(a: BigStruct, b: BigStruct) { println!(""); } #[no_stack_check] -#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn binding(a: i64, b: u64, c: f64) { let x = 0; println!(""); } #[no_stack_check] -#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn assignment(mut a: u64, b: u64, c: f64) { a = b; println!(""); } #[no_stack_check] -#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn function_call(x: u64, y: u64, z: f64) { println!("Hi!") } #[no_stack_check] -#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn identifier(x: u64, y: u64, z: f64) -> u64 { x } #[no_stack_check] -#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn return_expr(x: u64, y: u64, z: f64) -> u64 { return x; } #[no_stack_check] -#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 { x + y } #[no_stack_check] -#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn if_expr(x: u64, y: u64, z: f64) -> u64 { if x + y < 1000 { x @@ -322,7 +313,6 @@ fn if_expr(x: u64, y: u64, z: f64) -> u64 { } #[no_stack_check] -#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn while_expr(mut x: u64, y: u64, z: u64) -> u64 { while x + y < 1000 { x += z @@ -331,7 +321,6 @@ fn while_expr(mut x: u64, y: u64, z: u64) -> u64 { } #[no_stack_check] -#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 { loop { x += z; diff --git a/src/test/run-pass/issue-15080.rs b/src/test/run-pass/issue-15080.rs index 7b00ea4a520cd..cee0caeb465f5 100644 --- a/src/test/run-pass/issue-15080.rs +++ b/src/test/run-pass/issue-15080.rs @@ -16,12 +16,12 @@ fn main() { let mut result = vec!(); loop { - x = match x { - [1, n, 3, rest..] => { + x = match *x { + [1, n, 3, ref rest..] => { result.push(n); rest } - [n, rest..] => { + [n, ref rest..] => { result.push(n); rest } diff --git a/src/test/run-pass/issue-15104.rs b/src/test/run-pass/issue-15104.rs index b55754ee59b35..508360cb70110 100644 --- a/src/test/run-pass/issue-15104.rs +++ b/src/test/run-pass/issue-15104.rs @@ -16,9 +16,9 @@ fn main() { } fn count_members(v: &[usize]) -> usize { - match v { + match *v { [] => 0, [_] => 1, - [_x, xs..] => 1 + count_members(xs) + [_, ref xs..] => 1 + count_members(xs) } } diff --git a/src/test/run-pass/issue-16648.rs b/src/test/run-pass/issue-16648.rs index 384bd9df7cfed..e596bee8bfe9f 100644 --- a/src/test/run-pass/issue-16648.rs +++ b/src/test/run-pass/issue-16648.rs @@ -9,14 +9,15 @@ // except according to those terms. -#![feature(slice_patterns)] +#![feature(slice_patterns, rustc_attrs)] +#[rustc_mir] fn main() { let x: (isize, &[isize]) = (2, &[1, 2]); assert_eq!(match x { - (0, [_, _]) => 0, + (0, &[_, _]) => 0, (1, _) => 1, - (2, [_, _]) => 2, + (2, &[_, _]) => 2, (2, _) => 3, _ => 4 }, 2); diff --git a/src/test/run-pass/issue-30240.rs b/src/test/run-pass/issue-30240.rs new file mode 100644 index 0000000000000..3be661ce35e38 --- /dev/null +++ b/src/test/run-pass/issue-30240.rs @@ -0,0 +1,23 @@ +// 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. + +fn main() { + let &ref a = &[0i32] as &[_]; + assert_eq!(a, &[0i32] as &[_]); + + let &ref a = "hello"; + assert_eq!(a, "hello"); + + match "foo" { + "fool" => unreachable!(), + "foo" => {}, + ref _x => unreachable!() + } +} diff --git a/src/test/run-pass/issue-7784.rs b/src/test/run-pass/issue-7784.rs index badc013cd621f..0008825226ba0 100644 --- a/src/test/run-pass/issue-7784.rs +++ b/src/test/run-pass/issue-7784.rs @@ -11,6 +11,7 @@ #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] +#![feature(rustc_attrs)] use std::ops::Add; @@ -21,6 +22,7 @@ fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] { [a, b, b, a] } +#[rustc_mir] fn main() { assert_eq!(foo([1, 2, 3]), (1, 3, 6)); diff --git a/src/test/run-pass/match-unsized.rs b/src/test/run-pass/match-unsized.rs new file mode 100644 index 0000000000000..7253672a7ff47 --- /dev/null +++ b/src/test/run-pass/match-unsized.rs @@ -0,0 +1,18 @@ +// 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. + +fn main() { + let data: &'static str = "Hello, World!"; + match data { + &ref xs => { + assert_eq!(data, xs); + } + } +} diff --git a/src/test/run-pass/match-vec-alternatives.rs b/src/test/run-pass/match-vec-alternatives.rs index 43e0b442251bd..010c145521008 100644 --- a/src/test/run-pass/match-vec-alternatives.rs +++ b/src/test/run-pass/match-vec-alternatives.rs @@ -11,47 +11,53 @@ #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] +#![feature(rustc_attrs)] +#[rustc_mir] fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str { match (l1, l2) { - ([], []) => "both empty", - ([], [..]) | ([..], []) => "one empty", - ([..], [..]) => "both non-empty" + (&[], &[]) => "both empty", + (&[], &[..]) | (&[..], &[]) => "one empty", + (&[..], &[..]) => "both non-empty" } } +#[rustc_mir] fn match_vecs_cons<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str { match (l1, l2) { - ([], []) => "both empty", - ([], [_, ..]) | ([_, ..], []) => "one empty", - ([_, ..], [_, ..]) => "both non-empty" + (&[], &[]) => "both empty", + (&[], &[_, ..]) | (&[_, ..], &[]) => "one empty", + (&[_, ..], &[_, ..]) => "both non-empty" } } +#[rustc_mir] fn match_vecs_snoc<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str { match (l1, l2) { - ([], []) => "both empty", - ([], [.., _]) | ([.., _], []) => "one empty", - ([.., _], [.., _]) => "both non-empty" + (&[], &[]) => "both empty", + (&[], &[.., _]) | (&[.., _], &[]) => "one empty", + (&[.., _], &[.., _]) => "both non-empty" } } +#[rustc_mir] fn match_nested_vecs_cons<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str { match (l1, l2) { - (Some([]), Ok([])) => "Some(empty), Ok(empty)", - (Some([_, ..]), Ok(_)) | (Some([_, ..]), Err(())) => "Some(non-empty), any", - (None, Ok([])) | (None, Err(())) | (None, Ok([_])) => "None, Ok(less than one element)", - (None, Ok([_, _, ..])) => "None, Ok(at least two elements)", + (Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)", + (Some(&[_, ..]), Ok(_)) | (Some(&[_, ..]), Err(())) => "Some(non-empty), any", + (None, Ok(&[])) | (None, Err(())) | (None, Ok(&[_])) => "None, Ok(less than one element)", + (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)", _ => "other" } } +#[rustc_mir] fn match_nested_vecs_snoc<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str { match (l1, l2) { - (Some([]), Ok([])) => "Some(empty), Ok(empty)", - (Some([.., _]), Ok(_)) | (Some([.., _]), Err(())) => "Some(non-empty), any", - (None, Ok([])) | (None, Err(())) | (None, Ok([_])) => "None, Ok(less than one element)", - (None, Ok([.., _, _])) => "None, Ok(at least two elements)", + (Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)", + (Some(&[.., _]), Ok(_)) | (Some(&[.., _]), Err(())) => "Some(non-empty), any", + (None, Ok(&[])) | (None, Err(())) | (None, Ok(&[_])) => "None, Ok(less than one element)", + (None, Ok(&[.., _, _])) => "None, Ok(at least two elements)", _ => "other" } } diff --git a/src/test/run-pass/vec-matching-fold.rs b/src/test/run-pass/vec-matching-fold.rs index ee70ea58750d9..7a6129d311ee3 100644 --- a/src/test/run-pass/vec-matching-fold.rs +++ b/src/test/run-pass/vec-matching-fold.rs @@ -11,21 +11,28 @@ #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] +#![feature(rustc_attrs)] +use std::fmt::Debug; + +#[rustc_mir(graphviz="mir.gv")] fn foldl(values: &[T], initial: U, mut function: F) -> U where - U: Clone, + U: Clone+Debug, T:Debug, F: FnMut(U, &T) -> U, -{ - match values { - [ref head, tail..] => +{ match values { + &[ref head, ref tail..] => foldl(tail, function(initial, head), function), - [] => initial.clone() + &[] => { + // FIXME: call guards + let res = initial.clone(); res + } } } +#[rustc_mir] fn foldr(values: &[T], initial: U, mut function: F) @@ -34,9 +41,12 @@ fn foldr(values: &[T], F: FnMut(&T, U) -> U, { match values { - [head.., ref tail] => + &[ref head.., ref tail] => foldr(head, function(tail, initial), function), - [] => initial.clone() + &[] => { + // FIXME: call guards + let res = initial.clone(); res + } } } diff --git a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs index e7553c8e157e3..1093bc7c18b86 100644 --- a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs +++ b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs @@ -8,14 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] +#![feature(slice_patterns, rustc_attrs)] +#[rustc_mir] pub fn main() { let x = &[1, 2, 3, 4, 5]; let x: &[isize] = &[1, 2, 3, 4, 5]; if !x.is_empty() { let el = match x { - [1, ref tail..] => &tail[0], + &[1, ref tail..] => &tail[0], _ => unreachable!() }; println!("{}", *el); diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs index eedf27f857700..075709a63b5f5 100644 --- a/src/test/run-pass/vec-matching.rs +++ b/src/test/run-pass/vec-matching.rs @@ -11,7 +11,9 @@ #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] +#![feature(rustc_attrs)] +#[rustc_mir] fn a() { let x = [1]; match x { @@ -21,6 +23,7 @@ fn a() { } } +#[rustc_mir] fn b() { let x = [1, 2, 3]; match x { @@ -56,6 +59,48 @@ fn b() { } } + +#[rustc_mir] +fn b_slice() { + let x : &[_] = &[1, 2, 3]; + match x { + &[a, b, ref c..] => { + assert_eq!(a, 1); + assert_eq!(b, 2); + let expected: &[_] = &[3]; + assert_eq!(c, expected); + } + _ => unreachable!() + } + match x { + &[ref a.., b, c] => { + let expected: &[_] = &[1]; + assert_eq!(a, expected); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + _ => unreachable!() + } + match x { + &[a, ref b.., c] => { + assert_eq!(a, 1); + let expected: &[_] = &[2]; + assert_eq!(b, expected); + assert_eq!(c, 3); + } + _ => unreachable!() + } + match x { + &[a, b, c] => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + _ => unreachable!() + } +} + +#[rustc_mir] fn c() { let x = [1]; match x { @@ -64,6 +109,7 @@ fn c() { } } +#[rustc_mir] fn d() { let x = [1, 2, 3]; let branch = match x { @@ -75,17 +121,40 @@ fn d() { assert_eq!(branch, 1); } +#[rustc_mir] fn e() { let x: &[isize] = &[1, 2, 3]; - match x { - [1, 2] => (), - [..] => () - } + let a = match *x { + [1, 2] => 0, + [..] => 1, + }; + + assert_eq!(a, 1); + + let b = match *x { + [2, ..] => 0, + [1, 2, ..] => 1, + [_] => 2, + [..] => 3 + }; + + assert_eq!(b, 1); + + + let c = match *x { + [_, _, _, _, ..] => 0, + [1, 2, ..] => 1, + [_] => 2, + [..] => 3 + }; + + assert_eq!(c, 1); } pub fn main() { a(); b(); + b_slice(); c(); d(); e(); diff --git a/src/test/run-pass/vec-tail-matching.rs b/src/test/run-pass/vec-tail-matching.rs index 6cc7e3a072cf0..6084a0d07a114 100644 --- a/src/test/run-pass/vec-tail-matching.rs +++ b/src/test/run-pass/vec-tail-matching.rs @@ -11,26 +11,28 @@ #![feature(slice_patterns)] +#![feature(rustc_attrs)] struct Foo { - string: String + string: &'static str } +#[rustc_mir] pub fn main() { let x = [ - Foo { string: "foo".to_string() }, - Foo { string: "bar".to_string() }, - Foo { string: "baz".to_string() } + Foo { string: "foo" }, + Foo { string: "bar" }, + Foo { string: "baz" } ]; match x { - [ref first, tail..] => { - assert_eq!(first.string, "foo".to_string()); + [ref first, ref tail..] => { + assert_eq!(first.string, "foo"); assert_eq!(tail.len(), 2); - assert_eq!(tail[0].string, "bar".to_string()); - assert_eq!(tail[1].string, "baz".to_string()); + assert_eq!(tail[0].string, "bar"); + assert_eq!(tail[1].string, "baz"); - match tail { - [Foo { .. }, _, Foo { .. }, _tail..] => { + match *(tail as &[_]) { + [Foo { .. }, _, Foo { .. }, ref _tail..] => { unreachable!(); } [Foo { string: ref a }, Foo { string: ref b }] => { diff --git a/src/test/run-pass/zero_sized_subslice_match.rs b/src/test/run-pass/zero_sized_subslice_match.rs index 697508ae48889..00f4aa98a3e06 100644 --- a/src/test/run-pass/zero_sized_subslice_match.rs +++ b/src/test/run-pass/zero_sized_subslice_match.rs @@ -8,15 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(rustc_attrs)] #![feature(slice_patterns)] +#[rustc_mir] fn main() { let x = [(), ()]; // The subslice used to go out of bounds for zero-sized array items, check that this doesn't // happen anymore match x { - [_, y..] => assert_eq!(&x[1] as *const (), &y[0] as *const ()) + [_, ref y..] => assert_eq!(&x[1] as *const (), &y[0] as *const ()) } }