Skip to content

Commit

Permalink
Categorize upvars in Fn unboxed closures as freely aliasable
Browse files Browse the repository at this point in the history
This causes borrowck to correctly reject mutation or mutable borrows
of upvars in `Fn` unboxed closures since the closure environment is
aliasable.

This also tracks the responsible closure in the aliasability
information returned and uses it to give a helpful diagnostic.

Closes issue #17780
  • Loading branch information
bkoropoff committed Oct 5, 2014
1 parent ea3ab73 commit f74b1c4
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 2 deletions.
6 changes: 6 additions & 0 deletions src/librustc/middle/borrowck/check_loans.rs
Expand Up @@ -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());
}

_ => {}
}

Expand Down
7 changes: 7 additions & 0 deletions src/librustc/middle/borrowck/mod.rs
Expand Up @@ -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(
Expand Down
12 changes: 10 additions & 2 deletions src/librustc/middle/mem_categorization.rs
Expand Up @@ -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<ty::UnboxedClosureKind>), // by ref upvar from stack or unboxed closure
cat_upvar(ty::UpvarId, ty::UpvarBorrow,
Option<ty::UnboxedClosureKind>), // 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
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -1302,7 +1304,6 @@ impl cmt_ {

cat_rvalue(..) |
cat_local(..) |
cat_upvar(..) |
cat_deref(_, _, UnsafePtr(..)) => { // yes, it's aliasable, but...
None
}
Expand All @@ -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
Expand Down

0 comments on commit f74b1c4

Please sign in to comment.