]> git.lizzy.rs Git - rust.git/commitdiff
add hint to fix error for immutable ref in arg
authorMikhail Modin <mikhailm1@gmail.com>
Tue, 8 Nov 2016 06:21:53 +0000 (09:21 +0300)
committerMikhail Modin <mikhailm1@gmail.com>
Mon, 28 Nov 2016 21:32:34 +0000 (00:32 +0300)
21 files changed:
src/librustc_borrowck/borrowck/mod.rs
src/test/compile-fail/borrowck/borrowck-borrow-overloaded-auto-deref-mut.rs [deleted file]
src/test/compile-fail/borrowck/borrowck-borrow-overloaded-deref-mut.rs [deleted file]
src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs [deleted file]
src/test/compile-fail/borrowck/borrowck-call-method-from-mut-aliasable.rs [deleted file]
src/test/compile-fail/borrowck/borrowck-fn-in-const-b.rs [deleted file]
src/test/compile-fail/borrowck/borrowck-object-mutability.rs [deleted file]
src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.rs [new file with mode: 0644]
src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr [new file with mode: 0644]
src/test/ui/span/borrowck-borrow-overloaded-deref-mut.rs [new file with mode: 0644]
src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr [new file with mode: 0644]
src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs [new file with mode: 0644]
src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr [new file with mode: 0644]
src/test/ui/span/borrowck-call-method-from-mut-aliasable.rs [new file with mode: 0644]
src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr [new file with mode: 0644]
src/test/ui/span/borrowck-fn-in-const-b.rs [new file with mode: 0644]
src/test/ui/span/borrowck-fn-in-const-b.stderr [new file with mode: 0644]
src/test/ui/span/borrowck-object-mutability.rs [new file with mode: 0644]
src/test/ui/span/borrowck-object-mutability.stderr [new file with mode: 0644]
src/test/ui/span/mut-arg-hint.rs [new file with mode: 0644]
src/test/ui/span/mut-arg-hint.stderr [new file with mode: 0644]

index 5e54e333bb90ce469a431a8bf659388c6aa2a03a..0c52aacdbdb14745500b2dcf02614ed05af1a077 100644 (file)
@@ -24,7 +24,7 @@
 
 use rustc::dep_graph::DepNode;
 use rustc::hir::map as hir_map;
-use rustc::hir::map::blocks::FnParts;
+use rustc::hir::map::blocks::{FnParts, FnLikeNode};
 use rustc::cfg;
 use rustc::middle::dataflow::DataFlowContext;
 use rustc::middle::dataflow::BitwiseOperator;
@@ -970,51 +970,8 @@ fn region_end_span(&self, region: &'tcx ty::Region) -> Option<Span> {
 
     pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>,
         error_span: Span) {
-        let code = err.code;
-        match code {
-            err_mutbl => {
-                match err.cmt.note {
-                    mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => {
-                        // If this is an `Fn` closure, it simply can't mutate upvars.
-                        // If it's an `FnMut` closure, the original variable was declared immutable.
-                        // We need to determine which is the case here.
-                        let kind = match err.cmt.upvar().unwrap().cat {
-                            Categorization::Upvar(mc::Upvar { kind, .. }) => kind,
-                            _ => bug!()
-                        };
-                        if kind == ty::ClosureKind::Fn {
-                            db.span_help(
-                                self.tcx.map.span(upvar_id.closure_expr_id),
-                                "consider changing this closure to take \
-                                 self by mutable reference");
-                        }
-                    }
-                    _ => {
-                        if let Categorization::Local(local_id) = err.cmt.cat {
-                            let span = self.tcx.map.span(local_id);
-                            if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
-                                if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") {
-                                    db.span_label(error_span, &format!("cannot reborrow mutably"));
-                                    db.span_label(error_span, &format!("try removing `&mut` here"));
-                                } else {
-                                    if snippet.starts_with("ref ") {
-                                        db.span_label(span,
-                                            &format!("use `{}` here to make mutable",
-                                                snippet.replace("ref ", "ref mut ")));
-                                    } else if snippet != "self" {
-                                        db.span_label(span,
-                                            &format!("use `mut {}` here to make mutable", snippet));
-                                    }
-                                    db.span_label(error_span, &format!("cannot borrow mutably"));
-                                }
-                            } else {
-                                db.span_label(error_span, &format!("cannot borrow mutably"));
-                            }
-                        }
-                    }
-                }
-            }
-
+        match err.code {
+            err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span),
             err_out_of_scope(super_scope, sub_scope, cause) => {
                 let (value_kind, value_msg) = match err.cmt.cat {
                     mc::Categorization::Rvalue(_) =>
@@ -1135,6 +1092,86 @@ pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<
         }
     }
 
+    fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckError<'tcx>,
+                                    error_span: &Span) {
+        match err.cmt.note {
+            mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => {
+                // If this is an `Fn` closure, it simply can't mutate upvars.
+                // If it's an `FnMut` closure, the original variable was declared immutable.
+                // We need to determine which is the case here.
+                let kind = match err.cmt.upvar().unwrap().cat {
+                    Categorization::Upvar(mc::Upvar { kind, .. }) => kind,
+                    _ => bug!()
+                };
+                if kind == ty::ClosureKind::Fn {
+                    db.span_help(self.tcx.map.span(upvar_id.closure_expr_id),
+                                 "consider changing this closure to take \
+                                 self by mutable reference");
+                }
+            }
+            _ => {
+                if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
+                    if let Categorization::Local(local_id) = inner_cmt.cat {
+                        let parent = self.tcx.map.get_parent_node(local_id);
+                        let opt_fn_decl = FnLikeNode::from_node(self.tcx.map.get(parent))
+                            .map(|fn_like| fn_like.decl());
+
+                        if let Some(fn_decl) = opt_fn_decl {
+                            if let Some(ref arg) = fn_decl.inputs.iter()
+                                .find(|ref arg| arg.pat.id == local_id) {
+                                if let hir::TyRptr(
+                                    opt_lifetime,
+                                    hir::MutTy{mutbl: hir::Mutability::MutImmutable, ref ty}) =
+                                    arg.ty.node {
+                                    if let Some(lifetime) = opt_lifetime {
+                                        if let Ok(snippet) = self.tcx.sess.codemap()
+                                            .span_to_snippet(ty.span) {
+                                            if let Ok(lifetime_snippet) = self.tcx.sess.codemap()
+                                                .span_to_snippet(lifetime.span) {
+                                                    db.span_label(arg.ty.span,
+                                                                  &format!("use `&{} mut {}` \
+                                                                            here to make mutable",
+                                                                            lifetime_snippet,
+                                                                            snippet));
+                                            }
+                                        }
+                                    }
+                                    else if let Ok(snippet) = self.tcx.sess.codemap()
+                                        .span_to_snippet(arg.ty.span) {
+                                        if snippet.starts_with("&") {
+                                            db.span_label(arg.ty.span,
+                                                          &format!("use `{}` here to make mutable",
+                                                                   snippet.replace("&", "&mut ")));
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                } else if let Categorization::Local(local_id) = err.cmt.cat {
+                    let span = self.tcx.map.span(local_id);
+                    if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
+                        if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") {
+                            db.span_label(*error_span, &format!("cannot reborrow mutably"));
+                            db.span_label(*error_span, &format!("try removing `&mut` here"));
+                        } else {
+                            if snippet.starts_with("ref ") {
+                                db.span_label(span, &format!("use `{}` here to make mutable",
+                                                             snippet.replace("ref ", "ref mut ")));
+                            } else if snippet != "self" {
+                                db.span_label(span,
+                                              &format!("use `mut {}` here to make mutable",
+                                                       snippet));
+                            }
+                            db.span_label(*error_span, &format!("cannot borrow mutably"));
+                        }
+                    } else {
+                        db.span_label(*error_span, &format!("cannot borrow mutably"));
+                    }
+                }
+            }
+        }
+    }
     pub fn append_loan_path_to_string(&self,
                                       loan_path: &LoanPath<'tcx>,
                                       out: &mut String) {
diff --git a/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-auto-deref-mut.rs b/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-auto-deref-mut.rs
deleted file mode 100644 (file)
index 764d05b..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2014 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.
-
-// Test how overloaded deref interacts with borrows when DerefMut
-// is implemented.
-
-use std::ops::{Deref, DerefMut};
-
-struct Own<T> {
-    value: *mut T
-}
-
-impl<T> Deref for Own<T> {
-    type Target = T;
-
-    fn deref(&self) -> &T {
-        unsafe { &*self.value }
-    }
-}
-
-impl<T> DerefMut for Own<T> {
-    fn deref_mut(&mut self) -> &mut T {
-        unsafe { &mut *self.value }
-    }
-}
-
-struct Point {
-    x: isize,
-    y: isize
-}
-
-impl Point {
-    fn get(&self) -> (isize, isize) {
-        (self.x, self.y)
-    }
-
-    fn set(&mut self, x: isize, y: isize) {
-        self.x = x;
-        self.y = y;
-    }
-
-    fn x_ref(&self) -> &isize {
-        &self.x
-    }
-
-    fn y_mut(&mut self) -> &mut isize {
-        &mut self.y
-    }
-}
-
-fn deref_imm_field(x: Own<Point>) {
-    let __isize = &x.y;
-}
-
-fn deref_mut_field1(x: Own<Point>) {
-    let __isize = &mut x.y; //~ ERROR cannot borrow
-}
-
-fn deref_mut_field2(mut x: Own<Point>) {
-    let __isize = &mut x.y;
-}
-
-fn deref_extend_field(x: &Own<Point>) -> &isize {
-    &x.y
-}
-
-fn deref_extend_mut_field1(x: &Own<Point>) -> &mut isize {
-    &mut x.y //~ ERROR cannot borrow
-}
-
-fn deref_extend_mut_field2(x: &mut Own<Point>) -> &mut isize {
-    &mut x.y
-}
-
-fn deref_extend_mut_field3(x: &mut Own<Point>) {
-    // Hmm, this is unfortunate, because with box it would work,
-    // but it's presently the expected outcome. See `deref_extend_mut_field4`
-    // for the workaround.
-
-    let _x = &mut x.x;
-    let _y = &mut x.y; //~ ERROR cannot borrow
-}
-
-fn deref_extend_mut_field4<'a>(x: &'a mut Own<Point>) {
-    let p = &mut **x;
-    let _x = &mut p.x;
-    let _y = &mut p.y;
-}
-
-fn assign_field1<'a>(x: Own<Point>) {
-    x.y = 3; //~ ERROR cannot borrow
-}
-
-fn assign_field2<'a>(x: &'a Own<Point>) {
-    x.y = 3; //~ ERROR cannot borrow
-}
-
-fn assign_field3<'a>(x: &'a mut Own<Point>) {
-    x.y = 3;
-}
-
-fn assign_field4<'a>(x: &'a mut Own<Point>) {
-    let _p: &mut Point = &mut **x;
-    x.y = 3; //~ ERROR cannot borrow
-}
-
-fn deref_imm_method(x: Own<Point>) {
-    let __isize = x.get();
-}
-
-fn deref_mut_method1(x: Own<Point>) {
-    x.set(0, 0); //~ ERROR cannot borrow
-}
-
-fn deref_mut_method2(mut x: Own<Point>) {
-    x.set(0, 0);
-}
-
-fn deref_extend_method(x: &Own<Point>) -> &isize {
-    x.x_ref()
-}
-
-fn deref_extend_mut_method1(x: &Own<Point>) -> &mut isize {
-    x.y_mut() //~ ERROR cannot borrow
-}
-
-fn deref_extend_mut_method2(x: &mut Own<Point>) -> &mut isize {
-    x.y_mut()
-}
-
-fn assign_method1<'a>(x: Own<Point>) {
-    *x.y_mut() = 3; //~ ERROR cannot borrow
-}
-
-fn assign_method2<'a>(x: &'a Own<Point>) {
-    *x.y_mut() = 3; //~ ERROR cannot borrow
-}
-
-fn assign_method3<'a>(x: &'a mut Own<Point>) {
-    *x.y_mut() = 3;
-}
-
-pub fn main() {}
diff --git a/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-deref-mut.rs b/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-deref-mut.rs
deleted file mode 100644 (file)
index 34b926a..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2014 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.
-
-// Test how overloaded deref interacts with borrows when DerefMut
-// is implemented.
-
-use std::ops::{Deref, DerefMut};
-
-struct Own<T> {
-    value: *mut T
-}
-
-impl<T> Deref for Own<T> {
-    type Target = T;
-
-    fn deref<'a>(&'a self) -> &'a T {
-        unsafe { &*self.value }
-    }
-}
-
-impl<T> DerefMut for Own<T> {
-    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
-        unsafe { &mut *self.value }
-    }
-}
-
-fn deref_imm(x: Own<isize>) {
-    let __isize = &*x;
-}
-
-fn deref_mut1(x: Own<isize>) {
-    let __isize = &mut *x; //~ ERROR cannot borrow
-}
-
-fn deref_mut2(mut x: Own<isize>) {
-    let __isize = &mut *x;
-}
-
-fn deref_extend<'a>(x: &'a Own<isize>) -> &'a isize {
-    &**x
-}
-
-fn deref_extend_mut1<'a>(x: &'a Own<isize>) -> &'a mut isize {
-    &mut **x //~ ERROR cannot borrow
-}
-
-fn deref_extend_mut2<'a>(x: &'a mut Own<isize>) -> &'a mut isize {
-    &mut **x
-}
-
-fn assign1<'a>(x: Own<isize>) {
-    *x = 3; //~ ERROR cannot borrow
-}
-
-fn assign2<'a>(x: &'a Own<isize>) {
-    **x = 3; //~ ERROR cannot borrow
-}
-
-fn assign3<'a>(x: &'a mut Own<isize>) {
-    **x = 3;
-}
-
-pub fn main() {}
diff --git a/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs b/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs
deleted file mode 100644 (file)
index ba1ae64..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2014 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.
-
-#![feature(fn_traits)]
-
-// Ensure that invoking a closure counts as a unique immutable borrow
-
-type Fn<'a> = Box<FnMut() + 'a>;
-
-struct Test<'a> {
-    f: Box<FnMut() + 'a>
-}
-
-// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
-fn call<F>(mut f: F) where F: FnMut(Fn) {
-    f(Box::new(|| {
-    //~^ ERROR: cannot borrow `f` as mutable more than once
-        f((Box::new(|| {})))
-    }));
-}
-
-fn test1() {
-    call(|mut a| {
-        a.call_mut(());
-    });
-}
-
-fn test2<F>(f: &F) where F: FnMut() {
-    (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable
-}
-
-fn test3<F>(f: &mut F) where F: FnMut() {
-    (*f)();
-}
-
-fn test4(f: &Test) {
-    f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable
-}
-
-fn test5(f: &mut Test) {
-    f.f.call_mut(())
-}
-
-fn test6() {
-    let mut f = || {};
-    (|| {
-        f();
-    })();
-}
-
-fn test7() {
-    fn foo<F>(_: F) where F: FnMut(Box<FnMut(isize)>, isize) {}
-    let mut f = |g: Box<FnMut(isize)>, b: isize| {};
-    // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
-    f(Box::new(|a| {
-        foo(f);
-        //~^ ERROR cannot move `f` into closure because it is borrowed
-        //~| ERROR cannot move out of captured outer variable in an `FnMut` closure
-    }), 3);
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/borrowck/borrowck-call-method-from-mut-aliasable.rs b/src/test/compile-fail/borrowck/borrowck-call-method-from-mut-aliasable.rs
deleted file mode 100644 (file)
index bc0b667..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2012 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.
-
-struct Foo {
-    x: isize,
-}
-
-impl Foo {
-    pub fn f(&self) {}
-    pub fn h(&mut self) {}
-}
-
-fn a(x: &mut Foo) {
-    x.f();
-    x.h();
-}
-
-fn b(x: &Foo) {
-    x.f();
-    x.h(); //~ ERROR cannot borrow
-}
-
-fn main() {
-}
diff --git a/src/test/compile-fail/borrowck/borrowck-fn-in-const-b.rs b/src/test/compile-fail/borrowck/borrowck-fn-in-const-b.rs
deleted file mode 100644 (file)
index 7e29b2e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2014 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.
-
-// Check that we check fns appearing in constant declarations.
-// Issue #22382.
-
-// How about mutating an immutable vector?
-const MUTATE: fn(&Vec<String>) = {
-    fn broken(x: &Vec<String>) {
-        x.push(format!("this is broken"));
-        //~^ ERROR cannot borrow
-    }
-    broken
-};
-
-fn main() {
-}
diff --git a/src/test/compile-fail/borrowck/borrowck-object-mutability.rs b/src/test/compile-fail/borrowck/borrowck-object-mutability.rs
deleted file mode 100644 (file)
index 1bdc32b..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2012 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.
-
-
-trait Foo {
-    fn borrowed(&self);
-    fn borrowed_mut(&mut self);
-}
-
-fn borrowed_receiver(x: &Foo) {
-    x.borrowed();
-    x.borrowed_mut(); //~ ERROR cannot borrow
-}
-
-fn borrowed_mut_receiver(x: &mut Foo) {
-    x.borrowed();
-    x.borrowed_mut();
-}
-
-fn owned_receiver(x: Box<Foo>) {
-    x.borrowed();
-    x.borrowed_mut(); //~ ERROR cannot borrow
-}
-
-fn mut_owned_receiver(mut x: Box<Foo>) {
-    x.borrowed();
-    x.borrowed_mut();
-}
-
-fn main() {}
diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.rs b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.rs
new file mode 100644 (file)
index 0000000..764d05b
--- /dev/null
@@ -0,0 +1,150 @@
+// Copyright 2014 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.
+
+// Test how overloaded deref interacts with borrows when DerefMut
+// is implemented.
+
+use std::ops::{Deref, DerefMut};
+
+struct Own<T> {
+    value: *mut T
+}
+
+impl<T> Deref for Own<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        unsafe { &*self.value }
+    }
+}
+
+impl<T> DerefMut for Own<T> {
+    fn deref_mut(&mut self) -> &mut T {
+        unsafe { &mut *self.value }
+    }
+}
+
+struct Point {
+    x: isize,
+    y: isize
+}
+
+impl Point {
+    fn get(&self) -> (isize, isize) {
+        (self.x, self.y)
+    }
+
+    fn set(&mut self, x: isize, y: isize) {
+        self.x = x;
+        self.y = y;
+    }
+
+    fn x_ref(&self) -> &isize {
+        &self.x
+    }
+
+    fn y_mut(&mut self) -> &mut isize {
+        &mut self.y
+    }
+}
+
+fn deref_imm_field(x: Own<Point>) {
+    let __isize = &x.y;
+}
+
+fn deref_mut_field1(x: Own<Point>) {
+    let __isize = &mut x.y; //~ ERROR cannot borrow
+}
+
+fn deref_mut_field2(mut x: Own<Point>) {
+    let __isize = &mut x.y;
+}
+
+fn deref_extend_field(x: &Own<Point>) -> &isize {
+    &x.y
+}
+
+fn deref_extend_mut_field1(x: &Own<Point>) -> &mut isize {
+    &mut x.y //~ ERROR cannot borrow
+}
+
+fn deref_extend_mut_field2(x: &mut Own<Point>) -> &mut isize {
+    &mut x.y
+}
+
+fn deref_extend_mut_field3(x: &mut Own<Point>) {
+    // Hmm, this is unfortunate, because with box it would work,
+    // but it's presently the expected outcome. See `deref_extend_mut_field4`
+    // for the workaround.
+
+    let _x = &mut x.x;
+    let _y = &mut x.y; //~ ERROR cannot borrow
+}
+
+fn deref_extend_mut_field4<'a>(x: &'a mut Own<Point>) {
+    let p = &mut **x;
+    let _x = &mut p.x;
+    let _y = &mut p.y;
+}
+
+fn assign_field1<'a>(x: Own<Point>) {
+    x.y = 3; //~ ERROR cannot borrow
+}
+
+fn assign_field2<'a>(x: &'a Own<Point>) {
+    x.y = 3; //~ ERROR cannot borrow
+}
+
+fn assign_field3<'a>(x: &'a mut Own<Point>) {
+    x.y = 3;
+}
+
+fn assign_field4<'a>(x: &'a mut Own<Point>) {
+    let _p: &mut Point = &mut **x;
+    x.y = 3; //~ ERROR cannot borrow
+}
+
+fn deref_imm_method(x: Own<Point>) {
+    let __isize = x.get();
+}
+
+fn deref_mut_method1(x: Own<Point>) {
+    x.set(0, 0); //~ ERROR cannot borrow
+}
+
+fn deref_mut_method2(mut x: Own<Point>) {
+    x.set(0, 0);
+}
+
+fn deref_extend_method(x: &Own<Point>) -> &isize {
+    x.x_ref()
+}
+
+fn deref_extend_mut_method1(x: &Own<Point>) -> &mut isize {
+    x.y_mut() //~ ERROR cannot borrow
+}
+
+fn deref_extend_mut_method2(x: &mut Own<Point>) -> &mut isize {
+    x.y_mut()
+}
+
+fn assign_method1<'a>(x: Own<Point>) {
+    *x.y_mut() = 3; //~ ERROR cannot borrow
+}
+
+fn assign_method2<'a>(x: &'a Own<Point>) {
+    *x.y_mut() = 3; //~ ERROR cannot borrow
+}
+
+fn assign_method3<'a>(x: &'a mut Own<Point>) {
+    *x.y_mut() = 3;
+}
+
+pub fn main() {}
diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr
new file mode 100644 (file)
index 0000000..1109351
--- /dev/null
@@ -0,0 +1,86 @@
+error: cannot borrow immutable argument `x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24
+   |
+62 | fn deref_mut_field1(x: Own<Point>) {
+   |                     - use `mut x` here to make mutable
+63 |     let __isize = &mut x.y; //~ ERROR cannot borrow
+   |                        ^ cannot borrow mutably
+
+error: cannot borrow immutable borrowed content `*x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:75:10
+   |
+74 | fn deref_extend_mut_field1(x: &Own<Point>) -> &mut isize {
+   |                               ----------- use `&mut Own<Point>` here to make mutable
+75 |     &mut x.y //~ ERROR cannot borrow
+   |          ^
+
+error[E0499]: cannot borrow `*x` as mutable more than once at a time
+  --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:19
+   |
+87 |     let _x = &mut x.x;
+   |                   - first mutable borrow occurs here
+88 |     let _y = &mut x.y; //~ ERROR cannot borrow
+   |                   ^ second mutable borrow occurs here
+89 | }
+   | - first borrow ends here
+
+error: cannot borrow immutable argument `x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5
+   |
+97 | fn assign_field1<'a>(x: Own<Point>) {
+   |                      - use `mut x` here to make mutable
+98 |     x.y = 3; //~ ERROR cannot borrow
+   |     ^ cannot borrow mutably
+
+error: cannot borrow immutable borrowed content `*x` as mutable
+   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:102:5
+    |
+101 | fn assign_field2<'a>(x: &'a Own<Point>) {
+    |                         -------------- use `&'a mut Own<Point>` here to make mutable
+102 |     x.y = 3; //~ ERROR cannot borrow
+    |     ^
+
+error[E0499]: cannot borrow `*x` as mutable more than once at a time
+   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:111:5
+    |
+110 |     let _p: &mut Point = &mut **x;
+    |                                -- first mutable borrow occurs here
+111 |     x.y = 3; //~ ERROR cannot borrow
+    |     ^ second mutable borrow occurs here
+112 | }
+    | - first borrow ends here
+
+error: cannot borrow immutable argument `x` as mutable
+   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5
+    |
+118 | fn deref_mut_method1(x: Own<Point>) {
+    |                      - use `mut x` here to make mutable
+119 |     x.set(0, 0); //~ ERROR cannot borrow
+    |     ^ cannot borrow mutably
+
+error: cannot borrow immutable borrowed content `*x` as mutable
+   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:131:5
+    |
+130 | fn deref_extend_mut_method1(x: &Own<Point>) -> &mut isize {
+    |                                ----------- use `&mut Own<Point>` here to make mutable
+131 |     x.y_mut() //~ ERROR cannot borrow
+    |     ^
+
+error: cannot borrow immutable argument `x` as mutable
+   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6
+    |
+138 | fn assign_method1<'a>(x: Own<Point>) {
+    |                       - use `mut x` here to make mutable
+139 |     *x.y_mut() = 3; //~ ERROR cannot borrow
+    |      ^ cannot borrow mutably
+
+error: cannot borrow immutable borrowed content `*x` as mutable
+   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:143:6
+    |
+142 | fn assign_method2<'a>(x: &'a Own<Point>) {
+    |                          -------------- use `&'a mut Own<Point>` here to make mutable
+143 |     *x.y_mut() = 3; //~ ERROR cannot borrow
+    |      ^
+
+error: aborting due to 10 previous errors
+
diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.rs b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.rs
new file mode 100644 (file)
index 0000000..34b926a
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright 2014 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.
+
+// Test how overloaded deref interacts with borrows when DerefMut
+// is implemented.
+
+use std::ops::{Deref, DerefMut};
+
+struct Own<T> {
+    value: *mut T
+}
+
+impl<T> Deref for Own<T> {
+    type Target = T;
+
+    fn deref<'a>(&'a self) -> &'a T {
+        unsafe { &*self.value }
+    }
+}
+
+impl<T> DerefMut for Own<T> {
+    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
+        unsafe { &mut *self.value }
+    }
+}
+
+fn deref_imm(x: Own<isize>) {
+    let __isize = &*x;
+}
+
+fn deref_mut1(x: Own<isize>) {
+    let __isize = &mut *x; //~ ERROR cannot borrow
+}
+
+fn deref_mut2(mut x: Own<isize>) {
+    let __isize = &mut *x;
+}
+
+fn deref_extend<'a>(x: &'a Own<isize>) -> &'a isize {
+    &**x
+}
+
+fn deref_extend_mut1<'a>(x: &'a Own<isize>) -> &'a mut isize {
+    &mut **x //~ ERROR cannot borrow
+}
+
+fn deref_extend_mut2<'a>(x: &'a mut Own<isize>) -> &'a mut isize {
+    &mut **x
+}
+
+fn assign1<'a>(x: Own<isize>) {
+    *x = 3; //~ ERROR cannot borrow
+}
+
+fn assign2<'a>(x: &'a Own<isize>) {
+    **x = 3; //~ ERROR cannot borrow
+}
+
+fn assign3<'a>(x: &'a mut Own<isize>) {
+    **x = 3;
+}
+
+pub fn main() {}
diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
new file mode 100644 (file)
index 0000000..a5b7045
--- /dev/null
@@ -0,0 +1,34 @@
+error: cannot borrow immutable argument `x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25
+   |
+38 | fn deref_mut1(x: Own<isize>) {
+   |               - use `mut x` here to make mutable
+39 |     let __isize = &mut *x; //~ ERROR cannot borrow
+   |                         ^ cannot borrow mutably
+
+error: cannot borrow immutable borrowed content `*x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:51:11
+   |
+50 | fn deref_extend_mut1<'a>(x: &'a Own<isize>) -> &'a mut isize {
+   |                             -------------- use `&'a mut Own<isize>` here to make mutable
+51 |     &mut **x //~ ERROR cannot borrow
+   |           ^^
+
+error: cannot borrow immutable argument `x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6
+   |
+58 | fn assign1<'a>(x: Own<isize>) {
+   |                - use `mut x` here to make mutable
+59 |     *x = 3; //~ ERROR cannot borrow
+   |      ^ cannot borrow mutably
+
+error: cannot borrow immutable borrowed content `*x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:63:6
+   |
+62 | fn assign2<'a>(x: &'a Own<isize>) {
+   |                   -------------- use `&'a mut Own<isize>` here to make mutable
+63 |     **x = 3; //~ ERROR cannot borrow
+   |      ^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs
new file mode 100644 (file)
index 0000000..ba1ae64
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2014 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.
+
+#![feature(fn_traits)]
+
+// Ensure that invoking a closure counts as a unique immutable borrow
+
+type Fn<'a> = Box<FnMut() + 'a>;
+
+struct Test<'a> {
+    f: Box<FnMut() + 'a>
+}
+
+// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
+fn call<F>(mut f: F) where F: FnMut(Fn) {
+    f(Box::new(|| {
+    //~^ ERROR: cannot borrow `f` as mutable more than once
+        f((Box::new(|| {})))
+    }));
+}
+
+fn test1() {
+    call(|mut a| {
+        a.call_mut(());
+    });
+}
+
+fn test2<F>(f: &F) where F: FnMut() {
+    (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable
+}
+
+fn test3<F>(f: &mut F) where F: FnMut() {
+    (*f)();
+}
+
+fn test4(f: &Test) {
+    f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable
+}
+
+fn test5(f: &mut Test) {
+    f.f.call_mut(())
+}
+
+fn test6() {
+    let mut f = || {};
+    (|| {
+        f();
+    })();
+}
+
+fn test7() {
+    fn foo<F>(_: F) where F: FnMut(Box<FnMut(isize)>, isize) {}
+    let mut f = |g: Box<FnMut(isize)>, b: isize| {};
+    // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
+    f(Box::new(|a| {
+        foo(f);
+        //~^ ERROR cannot move `f` into closure because it is borrowed
+        //~| ERROR cannot move out of captured outer variable in an `FnMut` closure
+    }), 3);
+}
+
+fn main() {}
diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
new file mode 100644 (file)
index 0000000..16bb600
--- /dev/null
@@ -0,0 +1,43 @@
+error[E0499]: cannot borrow `f` as mutable more than once at a time
+  --> $DIR/borrowck-call-is-borrow-issue-12224.rs:23:16
+   |
+23 |     f(Box::new(|| {
+   |     -          ^^ second mutable borrow occurs here
+   |     |
+   |     first mutable borrow occurs here
+24 |     //~^ ERROR: cannot borrow `f` as mutable more than once
+25 |         f((Box::new(|| {})))
+   |         - borrow occurs due to use of `f` in closure
+26 |     }));
+   |       - first borrow ends here
+
+error: cannot borrow immutable borrowed content `*f` as mutable
+  --> $DIR/borrowck-call-is-borrow-issue-12224.rs:36:5
+   |
+35 | fn test2<F>(f: &F) where F: FnMut() {
+   |                -- use `&mut F` here to make mutable
+36 |     (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable
+   |     ^^^^
+
+error: cannot borrow immutable `Box` content `*f.f` as mutable
+  --> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5
+   |
+44 |     f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable
+   |     ^^^
+
+error[E0504]: cannot move `f` into closure because it is borrowed
+  --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13
+   |
+62 |     f(Box::new(|a| {
+   |     - borrow of `f` occurs here
+63 |         foo(f);
+   |             ^ move into closure occurs here
+
+error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
+  --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13
+   |
+63 |         foo(f);
+   |             ^ cannot move out of captured outer variable in an `FnMut` closure
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.rs b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.rs
new file mode 100644 (file)
index 0000000..bc0b667
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2012 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.
+
+struct Foo {
+    x: isize,
+}
+
+impl Foo {
+    pub fn f(&self) {}
+    pub fn h(&mut self) {}
+}
+
+fn a(x: &mut Foo) {
+    x.f();
+    x.h();
+}
+
+fn b(x: &Foo) {
+    x.f();
+    x.h(); //~ ERROR cannot borrow
+}
+
+fn main() {
+}
diff --git a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr
new file mode 100644 (file)
index 0000000..a1af1ca
--- /dev/null
@@ -0,0 +1,11 @@
+error: cannot borrow immutable borrowed content `*x` as mutable
+  --> $DIR/borrowck-call-method-from-mut-aliasable.rs:27:5
+   |
+25 | fn b(x: &Foo) {
+   |         ---- use `&mut Foo` here to make mutable
+26 |     x.f();
+27 |     x.h(); //~ ERROR cannot borrow
+   |     ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/span/borrowck-fn-in-const-b.rs b/src/test/ui/span/borrowck-fn-in-const-b.rs
new file mode 100644 (file)
index 0000000..7e29b2e
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2014 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.
+
+// Check that we check fns appearing in constant declarations.
+// Issue #22382.
+
+// How about mutating an immutable vector?
+const MUTATE: fn(&Vec<String>) = {
+    fn broken(x: &Vec<String>) {
+        x.push(format!("this is broken"));
+        //~^ ERROR cannot borrow
+    }
+    broken
+};
+
+fn main() {
+}
diff --git a/src/test/ui/span/borrowck-fn-in-const-b.stderr b/src/test/ui/span/borrowck-fn-in-const-b.stderr
new file mode 100644 (file)
index 0000000..41f549c
--- /dev/null
@@ -0,0 +1,10 @@
+error: cannot borrow immutable borrowed content `*x` as mutable
+  --> $DIR/borrowck-fn-in-const-b.rs:17:9
+   |
+16 |     fn broken(x: &Vec<String>) {
+   |                  ------------ use `&mut Vec<String>` here to make mutable
+17 |         x.push(format!("this is broken"));
+   |         ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/span/borrowck-object-mutability.rs b/src/test/ui/span/borrowck-object-mutability.rs
new file mode 100644 (file)
index 0000000..1bdc32b
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2012 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.
+
+
+trait Foo {
+    fn borrowed(&self);
+    fn borrowed_mut(&mut self);
+}
+
+fn borrowed_receiver(x: &Foo) {
+    x.borrowed();
+    x.borrowed_mut(); //~ ERROR cannot borrow
+}
+
+fn borrowed_mut_receiver(x: &mut Foo) {
+    x.borrowed();
+    x.borrowed_mut();
+}
+
+fn owned_receiver(x: Box<Foo>) {
+    x.borrowed();
+    x.borrowed_mut(); //~ ERROR cannot borrow
+}
+
+fn mut_owned_receiver(mut x: Box<Foo>) {
+    x.borrowed();
+    x.borrowed_mut();
+}
+
+fn main() {}
diff --git a/src/test/ui/span/borrowck-object-mutability.stderr b/src/test/ui/span/borrowck-object-mutability.stderr
new file mode 100644 (file)
index 0000000..32e4da1
--- /dev/null
@@ -0,0 +1,17 @@
+error: cannot borrow immutable borrowed content `*x` as mutable
+  --> $DIR/borrowck-object-mutability.rs:19:5
+   |
+17 | fn borrowed_receiver(x: &Foo) {
+   |                         ---- use `&mut Foo` here to make mutable
+18 |     x.borrowed();
+19 |     x.borrowed_mut(); //~ ERROR cannot borrow
+   |     ^
+
+error: cannot borrow immutable `Box` content `*x` as mutable
+  --> $DIR/borrowck-object-mutability.rs:29:5
+   |
+29 |     x.borrowed_mut(); //~ ERROR cannot borrow
+   |     ^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/span/mut-arg-hint.rs b/src/test/ui/span/mut-arg-hint.rs
new file mode 100644 (file)
index 0000000..296ee6c
--- /dev/null
@@ -0,0 +1,32 @@
+// 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.
+
+trait B {
+    fn foo(mut a: &String) {
+        a.push_str("bar");
+    }
+}
+
+pub fn foo<'a>(mut a: &'a String) {
+    a.push_str("foo");
+}
+
+struct A {}
+
+impl A {
+    pub fn foo(mut a: &String) {
+        a.push_str("foo");
+    }
+}
+
+fn main() {
+    foo(&"a".to_string());
+    A::foo(&"a".to_string());
+}
diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr
new file mode 100644 (file)
index 0000000..5e9a0b9
--- /dev/null
@@ -0,0 +1,26 @@
+error: cannot borrow immutable borrowed content `*a` as mutable
+  --> $DIR/mut-arg-hint.rs:13:9
+   |
+12 |     fn foo(mut a: &String) {
+   |                   ------- use `&mut String` here to make mutable
+13 |         a.push_str("bar");
+   |         ^
+
+error: cannot borrow immutable borrowed content `*a` as mutable
+  --> $DIR/mut-arg-hint.rs:18:5
+   |
+17 | pub fn foo<'a>(mut a: &'a String) {
+   |                       ---------- use `&'a mut String` here to make mutable
+18 |     a.push_str("foo");
+   |     ^
+
+error: cannot borrow immutable borrowed content `*a` as mutable
+  --> $DIR/mut-arg-hint.rs:25:9
+   |
+24 |     pub fn foo(mut a: &String) {
+   |                       ------- use `&mut String` here to make mutable
+25 |         a.push_str("foo");
+   |         ^
+
+error: aborting due to 3 previous errors
+