borrowck: consolidate `mut` suggestions

This converts all of borrowck's `mut` suggestions to a new
`mc::ImmutabilityBlame` API instead of the current mix of various hacks.

Fixes #35937.
Fixes #40823.
This commit is contained in:
Ariel Ben-Yehuda 2017-03-26 19:35:46 +03:00
parent 49c67bd632
commit 50728e5245
21 changed files with 305 additions and 208 deletions

View File

@ -194,76 +194,75 @@ pub struct cmt_<'tcx> {
pub type cmt<'tcx> = Rc<cmt_<'tcx>>;
pub enum ImmutabilityBlame<'tcx> {
ImmLocal(ast::NodeId),
ClosureEnv(ast::NodeId),
LocalDeref(ast::NodeId),
AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef)
}
impl<'tcx> cmt_<'tcx> {
pub fn get_def(&self) -> Option<ast::NodeId> {
match self.cat {
Categorization::Deref(ref cmt, ..) |
Categorization::Interior(ref cmt, _) |
Categorization::Downcast(ref cmt, _) => {
if let Categorization::Local(nid) = cmt.cat {
Some(nid)
} else {
None
}
fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef)
{
let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| {
bug!("interior cmt {:?} is not an ADT", self)
});
let variant_def = match self.cat {
Categorization::Downcast(_, variant_did) => {
adt_def.variant_with_id(variant_did)
}
_ => None
}
_ => {
assert!(adt_def.is_univariant());
&adt_def.variants[0]
}
};
let field_def = match field_name {
NamedField(name) => variant_def.field_named(name),
PositionalField(idx) => &variant_def.fields[idx]
};
(adt_def, field_def)
}
pub fn get_field(&self, name: ast::Name) -> Option<DefId> {
pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
match self.cat {
Categorization::Deref(ref cmt, ..) |
Categorization::Interior(ref cmt, _) |
Categorization::Downcast(ref cmt, _) => {
if let Categorization::Local(_) = cmt.cat {
if let ty::TyAdt(def, _) = self.ty.sty {
if def.is_struct() {
return def.struct_variant().find_field_named(name).map(|x| x.did);
Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) |
Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => {
// try to figure out where the immutable reference came from
match base_cmt.cat {
Categorization::Local(node_id) =>
Some(ImmutabilityBlame::LocalDeref(node_id)),
Categorization::Interior(ref base_cmt, InteriorField(field_name)) => {
let (adt_def, field_def) = base_cmt.resolve_field(field_name);
Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def))
}
Categorization::Upvar(Upvar { id, .. }) => {
if let NoteClosureEnv(..) = self.note {
Some(ImmutabilityBlame::ClosureEnv(id.closure_expr_id))
} else {
None
}
}
None
} else {
cmt.get_field(name)
_ => None
}
}
_ => None
}
}
pub fn get_field_name(&self) -> Option<ast::Name> {
match self.cat {
Categorization::Interior(_, ref ik) => {
if let InteriorKind::InteriorField(FieldName::NamedField(name)) = *ik {
Some(name)
} else {
None
}
Categorization::Local(node_id) => {
Some(ImmutabilityBlame::ImmLocal(node_id))
}
Categorization::Deref(ref cmt, ..) |
Categorization::Downcast(ref cmt, _) => {
cmt.get_field_name()
Categorization::Rvalue(..) |
Categorization::Upvar(..) |
Categorization::Deref(.., UnsafePtr(..)) => {
// This should not be reachable up to inference limitations.
None
}
_ => None,
}
}
pub fn get_arg_if_immutable(&self, map: &hir_map::Map) -> Option<ast::NodeId> {
match self.cat {
Categorization::Deref(ref cmt, ..) |
Categorization::Interior(ref cmt, _) |
Categorization::Downcast(ref cmt, _) => {
if let Categorization::Local(nid) = cmt.cat {
if let ty::TyAdt(_, _) = self.ty.sty {
if let ty::TyRef(_, ty::TypeAndMut{mutbl: MutImmutable, ..}) = cmt.ty.sty {
return Some(nid);
}
}
None
} else {
cmt.get_arg_if_immutable(map)
}
Categorization::Interior(ref base_cmt, _) |
Categorization::Downcast(ref base_cmt, _) |
Categorization::Deref(ref base_cmt, _, _) => {
base_cmt.immutability_blame()
}
Categorization::StaticItem => {
// Do we want to do something here?
None
}
_ => None
}
}
}
@ -1282,9 +1281,6 @@ pub enum Aliasability {
#[derive(Copy, Clone, Debug)]
pub enum AliasableReason {
AliasableBorrowed,
AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env
AliasableOther,
UnaliasableImmutable, // Created as needed upon seeing ImmutableUnique
AliasableStatic,
AliasableStaticMut,
}
@ -1324,23 +1320,13 @@ impl<'tcx> cmt_<'tcx> {
Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) |
Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
Categorization::Deref(ref b, _, Unique) |
Categorization::Downcast(ref b, _) |
Categorization::Interior(ref b, _) => {
// Aliasability depends on base cmt
b.freely_aliasable()
}
Categorization::Deref(ref b, _, Unique) => {
let sub = b.freely_aliasable();
if b.mutbl.is_mutable() {
// Aliasability depends on base cmt alone
sub
} else {
// Do not allow mutation through an immutable box.
ImmutableUnique(Box::new(sub))
}
}
Categorization::Rvalue(..) |
Categorization::Local(..) |
Categorization::Upvar(..) |
@ -1356,13 +1342,9 @@ impl<'tcx> cmt_<'tcx> {
}
}
Categorization::Deref(ref base, _, BorrowedPtr(ty::ImmBorrow, _)) |
Categorization::Deref(ref base, _, Implicit(ty::ImmBorrow, _)) => {
match base.cat {
Categorization::Upvar(Upvar{ id, .. }) =>
FreelyAliasable(AliasableClosure(id.closure_expr_id)),
_ => FreelyAliasable(AliasableBorrowed)
}
Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => {
FreelyAliasable(AliasableBorrowed)
}
}
}

View File

@ -188,14 +188,6 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
// user knows what they're doing in these cases.
Ok(())
}
(mc::Aliasability::ImmutableUnique(_), ty::MutBorrow) => {
bccx.report_aliasability_violation(
borrow_span,
loan_cause,
mc::AliasableReason::UnaliasableImmutable,
cmt);
Err(())
}
(mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) |
(mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => {
bccx.report_aliasability_violation(
@ -510,4 +502,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
self.move_error_collector.report_potential_errors(self.bccx);
}
}

View File

@ -34,6 +34,7 @@ use rustc::hir::def_id::DefId;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::middle::mem_categorization::ImmutabilityBlame;
use rustc::middle::region;
use rustc::ty::{self, TyCtxt};
@ -41,6 +42,7 @@ use std::fmt;
use std::rc::Rc;
use std::hash::{Hash, Hasher};
use syntax::ast;
use syntax::symbol::keywords;
use syntax_pos::{MultiSpan, Span};
use errors::DiagnosticBuilder;
@ -659,12 +661,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
self.tcx.sess.span_err_with_code(s, msg, code);
}
pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
let span = err.span.clone();
let mut immutable_field = None;
let mut local_def = None;
let msg = &match err.code {
let msg = match err.code {
err_mutbl => {
let descr = match err.cmt.note {
mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => {
@ -700,27 +700,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
BorrowViolation(euv::AutoUnsafe) |
BorrowViolation(euv::ForLoop) |
BorrowViolation(euv::MatchDiscriminant) => {
// Check for this field's definition to see if it is an immutable reference
// and suggest making it mutable if that is the case.
immutable_field = err.cmt.get_field_name()
.and_then(|name| err.cmt.get_field(name))
.and_then(|did| self.tcx.hir.as_local_node_id(did))
.and_then(|nid| {
if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(nid) {
return self.suggest_mut_for_immutable(&field.ty)
.map(|msg| (self.tcx.hir.span(nid), msg));
}
None
});
local_def = err.cmt.get_def()
.and_then(|nid| {
if !self.tcx.hir.is_argument(nid) {
Some(self.tcx.hir.span(nid))
} else {
None
}
});
format!("cannot borrow {} as mutable", descr)
}
BorrowViolation(euv::ClosureInvocation) => {
@ -746,16 +725,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
};
let mut db = self.struct_span_err(span, msg);
if let Some((span, msg)) = immutable_field {
db.span_label(span, &msg);
}
if let Some(let_span) = local_def {
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
db.span_label(let_span, &format!("consider changing this to `mut {}`", snippet));
}
}
db
self.struct_span_err(span, &msg)
}
pub fn report_aliasability_violation(&self,
@ -788,34 +758,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
};
let mut err = match cause {
mc::AliasableOther => {
struct_span_err!(
self.tcx.sess, span, E0385,
"{} in an aliasable location", prefix)
}
mc::AliasableReason::UnaliasableImmutable => {
struct_span_err!(
self.tcx.sess, span, E0386,
"{} in an immutable container", prefix)
}
mc::AliasableClosure(id) => {
let mut err = struct_span_err!(
self.tcx.sess, span, E0387,
"{} in a captured outer variable in an `Fn` closure", prefix);
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!(&mut err, self.tcx.hir.span(id),
"consider changing this to accept closures that implement `FnMut`");
} else {
span_help!(&mut err, self.tcx.hir.span(id),
"consider changing this closure to take self by mutable reference");
}
err
}
match cause {
mc::AliasableStatic |
mc::AliasableStaticMut => {
// This path cannot occur. It happens when we have an
@ -826,17 +769,38 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
// ignored.
span_bug!(span, "aliasability violation for static `{}`", prefix)
}
mc::AliasableBorrowed => {
let mut e = struct_span_err!(
mc::AliasableBorrowed => {}
};
let blame = cmt.immutability_blame();
let mut err = match blame {
Some(ImmutabilityBlame::ClosureEnv(id)) => {
let mut err = struct_span_err!(
self.tcx.sess, span, E0387,
"{} in a captured outer variable in an `Fn` closure", prefix);
// FIXME: the distinction between these 2 messages looks wrong.
let help = 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`.
"consider changing this to accept closures that implement `FnMut`"
} else {
"consider changing this closure to take self by mutable reference"
};
err.span_help(self.tcx.hir.span(id), help);
err
}
_ => {
let mut err = struct_span_err!(
self.tcx.sess, span, E0389,
"{} in a `&` reference", prefix);
e.span_label(span, &"assignment into an immutable reference");
if let Some(nid) = cmt.get_arg_if_immutable(&self.tcx.hir) {
self.immutable_argument_should_be_mut(nid, &mut e);
}
e
err.span_label(span, &"assignment into an immutable reference");
err
}
};
self.note_immutability_blame(&mut err, blame);
if is_closure {
err.help("closures behind references must be called via `&mut`");
@ -873,8 +837,20 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
None
}
fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) {
let parent = self.tcx.hir.get_parent_node(nid);
fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode {
let pat = match self.tcx.hir.get(node_id) {
hir_map::Node::NodeLocal(pat) => pat,
node => bug!("bad node for local: {:?}", node)
};
match pat.node {
hir::PatKind::Binding(mode, ..) => mode,
_ => bug!("local is not a binding: {:?}", pat)
}
}
fn local_ty(&self, node_id: ast::NodeId) -> Option<&hir::Ty> {
let parent = self.tcx.hir.get_parent_node(node_id);
let parent_node = self.tcx.hir.get(parent);
// The parent node is like a fn
@ -882,12 +858,72 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
// `nid`'s parent's `Body`
let fn_body = self.tcx.hir.body(fn_like.body());
// Get the position of `nid` in the arguments list
let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == nid);
let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id);
if let Some(i) = arg_pos {
// The argument's `Ty`
let arg_ty = &fn_like.decl().inputs[i];
if let Some(msg) = self.suggest_mut_for_immutable(&arg_ty) {
db.span_label(arg_ty.span, &msg);
Some(&fn_like.decl().inputs[i])
} else {
None
}
} else {
None
}
}
fn note_immutability_blame(&self,
db: &mut DiagnosticBuilder,
blame: Option<ImmutabilityBlame>) {
match blame {
None => {}
Some(ImmutabilityBlame::ClosureEnv(_)) => {}
Some(ImmutabilityBlame::ImmLocal(node_id)) => {
let let_span = self.tcx.hir.span(node_id);
if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) {
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
if self.tcx.hir.name(node_id) == keywords::SelfValue.name() &&
snippet != "self" {
// avoid suggesting `mut &self`.
return
}
db.span_label(
let_span,
&format!("consider changing this to `mut {}`", snippet)
);
}
}
}
Some(ImmutabilityBlame::LocalDeref(node_id)) => {
let let_span = self.tcx.hir.span(node_id);
match self.local_binding_mode(node_id) {
hir::BindingMode::BindByRef(..) => {
let snippet = self.tcx.sess.codemap().span_to_snippet(let_span);
if let Ok(snippet) = snippet {
db.span_label(
let_span,
&format!("consider changing this to `{}`",
snippet.replace("ref ", "ref mut "))
);
}
}
hir::BindingMode::BindByValue(..) => {
if let Some(local_ty) = self.local_ty(node_id) {
if let Some(msg) = self.suggest_mut_for_immutable(local_ty) {
db.span_label(local_ty.span, &msg);
}
}
}
}
}
Some(ImmutabilityBlame::AdtFieldDeref(_, field)) => {
let node_id = match self.tcx.hir.as_local_node_id(field.did) {
Some(node_id) => node_id,
None => return
};
if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) {
if let Some(msg) = self.suggest_mut_for_immutable(&field.ty) {
db.span_label(field.ty.span, &msg);
}
}
}
}
@ -941,10 +977,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
}
pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) {
fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) {
let error_span = err.span.clone();
match err.code {
err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span),
err_mutbl => {
self.note_and_explain_mutbl_error(db, &err, &error_span);
self.note_immutability_blame(db, err.cmt.immutability_blame());
}
err_out_of_scope(super_scope, sub_scope, cause) => {
let (value_kind, value_msg) = match err.cmt.cat {
mc::Categorization::Rvalue(..) =>
@ -1096,13 +1135,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \
_ => {
if let Categorization::Deref(..) = err.cmt.cat {
db.span_label(*error_span, &"cannot borrow as mutable");
if let Some(local_id) = err.cmt.get_arg_if_immutable(&self.tcx.hir) {
self.immutable_argument_should_be_mut(local_id, db);
} else if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
if let Categorization::Local(local_id) = inner_cmt.cat {
self.immutable_argument_should_be_mut(local_id, db);
}
}
} else if let Categorization::Local(local_id) = err.cmt.cat {
let span = self.tcx.hir.span(local_id);
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
@ -1110,14 +1142,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \
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 {

View File

@ -198,7 +198,7 @@ fn main() {
```
"##,
E0386: r##"
/*E0386: r##"
This error occurs when an attempt is made to mutate the target of a mutable
reference stored inside an immutable container.
@ -228,7 +228,7 @@ let x: i64 = 1;
let y: Box<Cell<_>> = Box::new(Cell::new(x));
y.set(2);
```
"##,
"##,*/
E0387: r##"
This error occurs when an attempt is made to mutate or mutably reference data
@ -1117,6 +1117,6 @@ fn main() {
}
register_diagnostics! {
E0385, // {} in an aliasable location
// E0385, // {} in an aliasable location
E0524, // two closures require unique access to `..` at the same time
}

View File

@ -27,7 +27,7 @@ fn main() {
x; //~ value moved here
let y = Int(2);
//~^use `mut y` here to make mutable
//~^ consider changing this to `mut y`
y //~ error: cannot borrow immutable local variable `y` as mutable
//~| cannot borrow
+=

View File

@ -23,7 +23,7 @@ fn indirect_write_to_imm_box() {
let mut x: isize = 1;
let y: Box<_> = box &mut x;
let p = &y;
***p = 2; //~ ERROR cannot assign to data in an immutable container
***p = 2; //~ ERROR cannot assign to data in a `&` reference
drop(p);
}
@ -43,7 +43,6 @@ fn borrow_in_var_from_var_via_imm_box() {
let p = &y;
let q = &***p;
**y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
//~^ ERROR cannot assign to data in an immutable container
drop(p);
drop(q);
}
@ -64,7 +63,6 @@ fn borrow_in_var_from_field_via_imm_box() {
let p = &y;
let q = &***p;
**y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
//~^ ERROR cannot assign to data in an immutable container
drop(p);
drop(q);
}
@ -85,7 +83,6 @@ fn borrow_in_field_from_var_via_imm_box() {
let p = &y.a;
let q = &***p;
**y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
//~^ ERROR cannot assign to data in an immutable container
drop(p);
drop(q);
}
@ -106,7 +103,6 @@ fn borrow_in_field_from_field_via_imm_box() {
let p = &y.a;
let q = &***p;
**y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
//~^ ERROR cannot assign to data in an immutable container
drop(p);
drop(q);
}

View File

@ -12,7 +12,7 @@ fn main() {
match op {
Some(ref v) => { let a = &mut v; },
//~^ ERROR:cannot borrow immutable
//~| use `ref mut v` here to make mutable
//~| cannot borrow mutably
None => {},
}
}

View File

@ -17,7 +17,7 @@ impl S {
}
fn func(arg: S) {
//~^ here to make mutable
//~^ consider changing this to `mut arg`
arg.mutate();
//~^ ERROR cannot borrow immutable argument
//~| cannot borrow mutably
@ -25,7 +25,7 @@ fn func(arg: S) {
fn main() {
let local = S;
//~^ here to make mutable
//~^ consider changing this to `mut local`
local.mutate();
//~^ ERROR cannot borrow immutable local variable
//~| cannot borrow mutably

View File

@ -2,7 +2,7 @@ error: cannot borrow immutable local variable `x` as mutable
--> $DIR/huge_multispan_highlight.rs:100:18
|
12 | let x = "foo";
| - use `mut x` here to make mutable
| - consider changing this to `mut x`
...
100 | let y = &mut x;
| ^ cannot borrow mutably

View File

@ -10,6 +10,8 @@ error: cannot borrow immutable argument `self` as mutable
error: cannot borrow immutable argument `self` as mutable
--> $DIR/issue-31424.rs:23:15
|
22 | fn bar(self: &mut Self) {
| ---- consider changing this to `mut self`
23 | (&mut self).bar();
| ^^^^ cannot borrow mutably

View File

@ -0,0 +1,31 @@
// Copyright 2017 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 {
pub v: Vec<String>
}
fn main() {
let f = Foo { v: Vec::new() };
f.v.push("cat".to_string());
}
struct S {
x: i32,
}
fn foo() {
let s = S { x: 42 };
s.x += 1;
}
fn bar(s: S) {
s.x += 1;
}

View File

@ -0,0 +1,26 @@
error: cannot borrow immutable field `f.v` as mutable
--> $DIR/issue-35937.rs:17:5
|
16 | let f = Foo { v: Vec::new() };
| - consider changing this to `mut f`
17 | f.v.push("cat".to_string());
| ^^^ cannot mutably borrow immutable field
error: cannot assign to immutable field `s.x`
--> $DIR/issue-35937.rs:26:5
|
25 | let s = S { x: 42 };
| - consider changing this to `mut s`
26 | s.x += 1;
| ^^^^^^^^ cannot mutably borrow immutable field
error: cannot assign to immutable field `s.x`
--> $DIR/issue-35937.rs:30:5
|
29 | fn bar(s: S) {
| - consider changing this to `mut s`
30 | s.x += 1;
| ^^^^^^^^ cannot mutably borrow immutable field
error: aborting due to 3 previous errors

View File

@ -2,7 +2,7 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable
--> $DIR/issue-38147-2.rs:17:9
|
12 | s: &'a String
| ------------- use `&'a mut String` here to make mutable
| ---------- use `&'a mut String` here to make mutable
...
17 | self.s.push('x');
| ^^^^^^ cannot borrow as mutable

View File

@ -2,10 +2,8 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable
--> $DIR/issue-38147-3.rs:17:9
|
12 | s: &'a String
| ------------- use `&'a mut String` here to make mutable
| ---------- use `&'a mut String` here to make mutable
...
16 | fn f(&self) {
| ----- use `&mut self` here to make mutable
17 | self.s.push('x');
| ^^^^^^ cannot borrow as mutable

View File

@ -8,15 +8,20 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
enum X {
pub enum X {
Y
}
struct Z {
pub struct Z {
x: X
}
fn main() {
pub fn main() {
let z = Z { x: X::Y };
let _ = &mut z.x;
}
pub fn with_arg(z: Z, w: &Z) {
let _ = &mut z.x;
let _ = &mut w.x;
}

View File

@ -6,5 +6,22 @@ error: cannot borrow immutable field `z.x` as mutable
21 | let _ = &mut z.x;
| ^^^ cannot mutably borrow immutable field
error: aborting due to previous error
error: cannot borrow immutable field `z.x` as mutable
--> $DIR/issue-39544.rs:25:18
|
24 | pub fn with_arg(z: Z, w: &Z) {
| - consider changing this to `mut z`
25 | let _ = &mut z.x;
| ^^^ cannot mutably borrow immutable field
error: cannot borrow immutable field `w.x` as mutable
--> $DIR/issue-39544.rs:26:18
|
24 | pub fn with_arg(z: Z, w: &Z) {
| -- use `&mut Z` here to make mutable
25 | let _ = &mut z.x;
26 | let _ = &mut w.x;
| ^^^ cannot mutably borrow immutable field
error: aborting due to 3 previous errors

View File

@ -0,0 +1,14 @@
// Copyright 2017 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 main() {
let mut buf = &[1, 2, 3, 4];
buf.iter_mut();
}

View File

@ -0,0 +1,8 @@
error: cannot borrow immutable borrowed content `*buf` as mutable
--> $DIR/issue-40823.rs:13:5
|
13 | buf.iter_mut();
| ^^^ cannot borrow as mutable
error: aborting due to previous error

View File

@ -2,7 +2,7 @@ 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
| - consider changing this to `mut x`
63 | let __isize = &mut x.y; //~ ERROR cannot borrow
| ^ cannot borrow mutably
@ -28,7 +28,7 @@ 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
| - consider changing this to `mut x`
98 | x.y = 3; //~ ERROR cannot borrow
| ^ cannot borrow mutably
@ -54,7 +54,7 @@ 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
| - consider changing this to `mut x`
119 | x.set(0, 0); //~ ERROR cannot borrow
| ^ cannot borrow mutably
@ -70,7 +70,7 @@ 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
| - consider changing this to `mut x`
139 | *x.y_mut() = 3; //~ ERROR cannot borrow
| ^ cannot borrow mutably

View File

@ -2,7 +2,7 @@ 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
| - consider changing this to `mut x`
39 | let __isize = &mut *x; //~ ERROR cannot borrow
| ^ cannot borrow mutably
@ -18,7 +18,7 @@ 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
| - consider changing this to `mut x`
59 | *x = 3; //~ ERROR cannot borrow
| ^ cannot borrow mutably

View File

@ -10,6 +10,9 @@ error: cannot borrow immutable borrowed content `*x` as mutable
error: cannot borrow immutable `Box` content `*x` as mutable
--> $DIR/borrowck-object-mutability.rs:29:5
|
27 | fn owned_receiver(x: Box<Foo>) {
| - consider changing this to `mut x`
28 | x.borrowed();
29 | x.borrowed_mut(); //~ ERROR cannot borrow
| ^ cannot borrow as mutable