diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index d90907888e314c60f4b18b8297395cb121b3dbef..e5271cfde5a447f63063c74076afef3d430c07cf 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -770,16 +770,7 @@ pub fn report_aliasability_violation(&self, 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 @@ pub fn report_aliasability_violation(&self, 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 0000000000000000000000000000000000000000..f9a79dbb9c32a2f91c0e6e8926095f452cb2f889 --- /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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn call_it(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 + }); +}