about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorBrian Koropoff <bkoropoff@gmail.com>2014-10-04 14:06:08 -0700
committerBrian Koropoff <bkoropoff@gmail.com>2014-10-05 00:24:10 -0700
commitf74b1c4ee255ab7cd2706896bced45f14e1ccc1a (patch)
tree481c425b441cce2c9760b4d3126f3ba618cbebe7 /src
parentea3ab731a3c762829e3f2bec5bfbaa3a3a84689f (diff)
downloadrust-f74b1c4ee255ab7cd2706896bced45f14e1ccc1a.tar.gz
rust-f74b1c4ee255ab7cd2706896bced45f14e1ccc1a.zip
Categorize upvars in `Fn` unboxed closures as freely aliasable
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
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs6
-rw-r--r--src/librustc/middle/borrowck/mod.rs7
-rw-r--r--src/librustc/middle/mem_categorization.rs12
3 files changed, 23 insertions, 2 deletions
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index e114eb88705..df18ec30f0e 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 710193188ee..a86ae420065 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 207722eba00..9a0885ca301 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<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
@@ -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