about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs22
-rw-r--r--src/test/compile-fail/issue-21600.rs27
2 files changed, 38 insertions, 11 deletions
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index d90907888e3..e5271cfde5a 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -770,16 +770,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
             MutabilityViolation => {
                 "cannot assign to data"
             }
-            BorrowViolation(euv::ClosureCapture(_)) => {
-                // I don't think we can get aliasability violations
-                // with closure captures, so no need to come up with a
-                // good error message. The reason this cannot happen
-                // is because we only capture local variables in
-                // closures, and those are never aliasable.
-                self.tcx.sess.span_bug(
-                    span,
-                    "aliasability violation with closure");
-            }
+            BorrowViolation(euv::ClosureCapture(_)) |
             BorrowViolation(euv::OverloadedOperator) |
             BorrowViolation(euv::AddrOf) |
             BorrowViolation(euv::AutoRef) |
@@ -809,8 +800,17 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                 self.tcx.sess.span_err(span,
                                        format!("{} in a captured outer \
                                                variable in an `Fn` closure", prefix).as_slice());
-                span_help!(self.tcx.sess, self.tcx.map.span(id),
+                if let BorrowViolation(euv::ClosureCapture(_)) = kind {
+                    // The aliasability violation with closure captures can
+                    // happen for nested closures, so we know the enclosing
+                    // closure incorrectly accepts an `Fn` while it needs to
+                    // be `FnMut`.
+                    span_help!(self.tcx.sess, self.tcx.map.span(id),
+                           "consider changing this to accept closures that implement `FnMut`");
+                } else {
+                    span_help!(self.tcx.sess, self.tcx.map.span(id),
                            "consider changing this closure to take self by mutable reference");
+                }
             }
             mc::AliasableStatic(..) |
             mc::AliasableStaticMut(..) => {
diff --git a/src/test/compile-fail/issue-21600.rs b/src/test/compile-fail/issue-21600.rs
new file mode 100644
index 00000000000..f9a79dbb9c3
--- /dev/null
+++ b/src/test/compile-fail/issue-21600.rs
@@ -0,0 +1,27 @@
+// Copyright 2015 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn call_it<F>(f: F) where F: Fn() { f(); }
+
+struct A;
+
+impl A {
+    fn gen(&self) {}
+    fn gen_mut(&mut self) {}
+}
+
+fn main() {
+    let mut x = A;
+    call_it(|| {    //~ HELP consider changing this to accept closures that implement `FnMut`
+        call_it(|| x.gen());
+        call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer
+        //~^ ERROR cannot borrow data mutably in a captured outer
+    });
+}