diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index e114eb88705bf..df18ec30f0ee3 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -854,6 +854,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { check_for_aliasability_violation(this, span, b.clone()); } + mc::cat_copied_upvar(mc::CopiedUpvar { + kind: mc::Unboxed(ty::FnUnboxedClosureKind), ..}) => { + // Prohibit writes to capture-by-move upvars in non-once closures + check_for_aliasability_violation(this, span, guarantor.clone()); + } + _ => {} } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 710193188eed3..a86ae42006595 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -728,6 +728,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { format!("{} in an aliasable location", prefix).as_slice()); } + mc::AliasableClosure(id) => { + self.tcx.sess.span_err(span, + format!("{} in a free variable from an \ + immutable unboxed closure", prefix).as_slice()); + span_note!(self.tcx.sess, self.tcx.map.span(id), + "consider changing this closure to take self by mutable reference"); + } mc::AliasableStatic(..) | mc::AliasableStaticMut(..) => { self.tcx.sess.span_err( diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 207722eba00e4..9a0885ca30135 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -83,7 +83,8 @@ 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, Option), // by ref upvar from stack or unboxed 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 @@ -1246,6 +1247,7 @@ pub enum InteriorSafety { pub enum AliasableReason { AliasableBorrowed, + AliasableClosure(ast::NodeId), // Aliasable due to capture by unboxed closure expr AliasableOther, AliasableStatic(InteriorSafety), AliasableStaticMut(InteriorSafety), @@ -1302,7 +1304,6 @@ impl cmt_ { cat_rvalue(..) | cat_local(..) | - cat_upvar(..) | cat_deref(_, _, UnsafePtr(..)) => { // yes, it's aliasable, but... None } @@ -1317,6 +1318,13 @@ impl cmt_ { } } + cat_upvar(ty::UpvarId { closure_expr_id: id, .. }, _, + Some(ty::FnUnboxedClosureKind)) => { + Some(AliasableClosure(id)) + } + + cat_upvar(..) => None, + cat_static_item(..) => { let int_safe = if ty::type_interior_is_unsafe(ctxt, self.ty) { InteriorUnsafe