From ea3ab731a3c762829e3f2bec5bfbaa3a3a84689f Mon Sep 17 00:00:00 2001 From: Brian Koropoff Date: Sat, 4 Oct 2014 14:04:10 -0700 Subject: [PATCH] Track kind of closure in upvar categorization Keep track of the kind of closure responsible for an upvar --- .../borrowck/gather_loans/gather_moves.rs | 13 +++-- .../borrowck/gather_loans/move_error.rs | 11 +++- .../borrowck/gather_loans/restrictions.rs | 2 +- src/librustc/middle/borrowck/mod.rs | 12 +++-- src/librustc/middle/mem_categorization.rs | 50 +++++++++++++------ src/librustc/middle/typeck/check/regionck.rs | 6 +-- 6 files changed, 61 insertions(+), 33 deletions(-) diff --git a/src/librustc/middle/borrowck/gather_loans/gather_moves.rs b/src/librustc/middle/borrowck/gather_loans/gather_moves.rs index 1ae512a244c0..cd67169ff569 100644 --- a/src/librustc/middle/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc/middle/borrowck/gather_loans/gather_moves.rs @@ -133,16 +133,15 @@ fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt, mc::cat_deref(_, _, mc::BorrowedPtr(..)) | mc::cat_deref(_, _, mc::Implicit(..)) | mc::cat_deref(_, _, mc::UnsafePtr(..)) | - mc::cat_upvar(..) | mc::cat_static_item | - mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => { + mc::cat_upvar(..) | mc::cat_static_item => { Some(cmt.clone()) } - // Can move out of captured upvars only if the destination closure - // type is 'once'. 1-shot stack closures emit the copied_upvar form - // (see mem_categorization.rs). - mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Once, .. }) => { - None + mc::cat_copied_upvar(mc::CopiedUpvar { kind: kind, .. }) => { + match kind.onceness() { + ast::Once => None, + ast::Many => Some(cmt.clone()) + } } mc::cat_rvalue(..) | diff --git a/src/librustc/middle/borrowck/gather_loans/move_error.rs b/src/librustc/middle/borrowck/gather_loans/move_error.rs index 1b18d07f5905..29677cf89714 100644 --- a/src/librustc/middle/borrowck/gather_loans/move_error.rs +++ b/src/librustc/middle/borrowck/gather_loans/move_error.rs @@ -115,8 +115,15 @@ fn report_cannot_move_out_of(bccx: &BorrowckCtxt, move_from: mc::cmt) { mc::cat_deref(_, _, mc::BorrowedPtr(..)) | mc::cat_deref(_, _, mc::Implicit(..)) | mc::cat_deref(_, _, mc::UnsafePtr(..)) | - mc::cat_upvar(..) | mc::cat_static_item | - mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => { + mc::cat_upvar(..) | mc::cat_static_item => { + bccx.span_err( + move_from.span, + format!("cannot move out of {}", + bccx.cmt_to_string(&*move_from)).as_slice()); + } + + mc::cat_copied_upvar(mc::CopiedUpvar { kind: kind, .. }) + if kind.onceness() == ast::Many => { bccx.span_err( move_from.span, format!("cannot move out of {}", diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index 067a73fcc9b7..f30a370d0685 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -72,7 +72,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { SafeIf(lp.clone(), vec![lp]) } - mc::cat_upvar(upvar_id, _) => { + mc::cat_upvar(upvar_id, _, _) => { // R-Variable, captured into closure let lp = Rc::new(LpUpvar(upvar_id)); SafeIf(lp.clone(), vec![lp]) diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 234afc7ae7a8..710193188eed 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -354,8 +354,12 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option> { match cmt.cat { mc::cat_rvalue(..) | - mc::cat_static_item | - mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => { + mc::cat_static_item => { + None + } + + mc::cat_copied_upvar(mc::CopiedUpvar { kind: kind, .. }) + if kind.onceness() == ast::Many => { None } @@ -363,9 +367,9 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option> { Some(Rc::new(LpVar(id))) } - mc::cat_upvar(ty::UpvarId {var_id: id, closure_expr_id: proc_id}, _) | + mc::cat_upvar(ty::UpvarId {var_id: id, closure_expr_id: proc_id}, _, _) | mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id: id, - onceness: _, + kind: _, capturing_proc: proc_id }) => { let upvar_id = ty::UpvarId{ var_id: id, closure_expr_id: proc_id }; Some(Rc::new(LpUpvar(upvar_id))) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 605d3f6d6ced..207722eba00e 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -83,7 +83,7 @@ pub enum categorization { cat_rvalue(ty::Region), // temporary val, argument is its scope cat_static_item, cat_copied_upvar(CopiedUpvar), // upvar copied into proc env - cat_upvar(ty::UpvarId, ty::UpvarBorrow), // by ref upvar from stack closure + cat_upvar(ty::UpvarId, ty::UpvarBorrow, Option), // by ref upvar from stack or unboxed closure cat_local(ast::NodeId), // local variable cat_deref(cmt, uint, PointerKind), // deref of a ptr cat_interior(cmt, InteriorKind), // something interior: field, tuple, etc @@ -93,10 +93,27 @@ pub enum categorization { // (*1) downcast is only required if the enum has more than one variant } +#[deriving(Clone, PartialEq)] +pub enum CopiedUpvarKind { + Boxed(ast::Onceness), + Unboxed(ty::UnboxedClosureKind) +} + +impl CopiedUpvarKind { + pub fn onceness(&self) -> ast::Onceness { + match *self { + Boxed(onceness) => onceness, + Unboxed(ty::FnUnboxedClosureKind) | + Unboxed(ty::FnMutUnboxedClosureKind) => ast::Many, + Unboxed(ty::FnOnceUnboxedClosureKind) => ast::Once + } + } +} + #[deriving(Clone, PartialEq)] pub struct CopiedUpvar { pub upvar_id: ast::NodeId, - pub onceness: ast::Onceness, + pub kind: CopiedUpvarKind, pub capturing_proc: ast::NodeId, } @@ -571,14 +588,14 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { }; if var_is_refd { - self.cat_upvar(id, span, var_id, fn_node_id) + self.cat_upvar(id, span, var_id, fn_node_id, None) } else { Ok(Rc::new(cmt_ { id:id, span:span, cat:cat_copied_upvar(CopiedUpvar { upvar_id: var_id, - onceness: closure_ty.onceness, + kind: Boxed(closure_ty.onceness), capturing_proc: fn_node_id, }), mutbl: MutabilityCategory::from_local(self.tcx(), var_id), @@ -591,20 +608,15 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { .unboxed_closures() .borrow(); let kind = unboxed_closures.get(&closure_id).kind; - let onceness = match kind { - ty::FnUnboxedClosureKind | - ty::FnMutUnboxedClosureKind => ast::Many, - ty::FnOnceUnboxedClosureKind => ast::Once, - }; if self.typer.capture_mode(fn_node_id) == ast::CaptureByRef { - self.cat_upvar(id, span, var_id, fn_node_id) + self.cat_upvar(id, span, var_id, fn_node_id, Some(kind)) } else { Ok(Rc::new(cmt_ { id: id, span: span, cat: cat_copied_upvar(CopiedUpvar { upvar_id: var_id, - onceness: onceness, + kind: Unboxed(kind), capturing_proc: fn_node_id, }), mutbl: MutabilityCategory::from_local(self.tcx(), var_id), @@ -638,7 +650,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { id: ast::NodeId, span: Span, var_id: ast::NodeId, - fn_node_id: ast::NodeId) + fn_node_id: ast::NodeId, + kind: Option) -> McResult { /*! * Upvars through a closure are in fact indirect @@ -666,7 +679,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { let base_cmt = Rc::new(cmt_ { id:id, span:span, - cat:cat_upvar(upvar_id, upvar_borrow), + cat:cat_upvar(upvar_id, upvar_borrow, kind), mutbl:McImmutable, ty:upvar_ty, }); @@ -1287,7 +1300,6 @@ impl cmt_ { b.freely_aliasable(ctxt) } - cat_copied_upvar(CopiedUpvar {onceness: ast::Once, ..}) | cat_rvalue(..) | cat_local(..) | cat_upvar(..) | @@ -1295,8 +1307,14 @@ impl cmt_ { None } - cat_copied_upvar(CopiedUpvar {onceness: ast::Many, ..}) => { - Some(AliasableOther) + cat_copied_upvar(CopiedUpvar {kind: kind, capturing_proc: id, ..}) => { + match kind { + Boxed(ast::Once) | + Unboxed(ty::FnOnceUnboxedClosureKind) | + Unboxed(ty::FnMutUnboxedClosureKind) => None, + Boxed(_) => Some(AliasableOther), + Unboxed(_) => Some(AliasableClosure(id)) + } } cat_static_item(..) => { diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 058b3ac9e6ec..f533079be69b 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -1552,7 +1552,7 @@ fn link_reborrowed_region(rcx: &Rcx, // Detect references to an upvar `x`: let cause = match ref_cmt.cat { - mc::cat_upvar(ref upvar_id, _) => { + mc::cat_upvar(ref upvar_id, _, _) => { let mut upvar_borrow_map = rcx.fcx.inh.upvar_borrow_map.borrow_mut(); match upvar_borrow_map.find_mut(upvar_id) { @@ -1686,7 +1686,7 @@ fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx, mc::cat_deref(base, _, mc::BorrowedPtr(..)) | mc::cat_deref(base, _, mc::Implicit(..)) => { match base.cat { - mc::cat_upvar(ref upvar_id, _) => { + mc::cat_upvar(ref upvar_id, _, _) => { // if this is an implicit deref of an // upvar, then we need to modify the // borrow_kind of the upvar to make sure it @@ -1739,7 +1739,7 @@ fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) { mc::cat_deref(base, _, mc::BorrowedPtr(..)) | mc::cat_deref(base, _, mc::Implicit(..)) => { match base.cat { - mc::cat_upvar(ref upvar_id, _) => { + mc::cat_upvar(ref upvar_id, _, _) => { // if this is an implicit deref of an // upvar, then we need to modify the // borrow_kind of the upvar to make sure it