Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 50728e5

Browse files
committedMar 26, 2017
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 rust-lang#35937. Fixes rust-lang#40823.
1 parent 49c67bd commit 50728e5

21 files changed

+304
-207
lines changed
 

‎src/librustc/middle/mem_categorization.rs

Lines changed: 61 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -194,76 +194,75 @@ pub struct cmt_<'tcx> {
194194

195195
pub type cmt<'tcx> = Rc<cmt_<'tcx>>;
196196

197+
pub enum ImmutabilityBlame<'tcx> {
198+
ImmLocal(ast::NodeId),
199+
ClosureEnv(ast::NodeId),
200+
LocalDeref(ast::NodeId),
201+
AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef)
202+
}
203+
197204
impl<'tcx> cmt_<'tcx> {
198-
pub fn get_def(&self) -> Option<ast::NodeId> {
199-
match self.cat {
200-
Categorization::Deref(ref cmt, ..) |
201-
Categorization::Interior(ref cmt, _) |
202-
Categorization::Downcast(ref cmt, _) => {
203-
if let Categorization::Local(nid) = cmt.cat {
204-
Some(nid)
205-
} else {
206-
None
207-
}
205+
fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef)
206+
{
207+
let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| {
208+
bug!("interior cmt {:?} is not an ADT", self)
209+
});
210+
let variant_def = match self.cat {
211+
Categorization::Downcast(_, variant_did) => {
212+
adt_def.variant_with_id(variant_did)
208213
}
209-
_ => None
210-
}
214+
_ => {
215+
assert!(adt_def.is_univariant());
216+
&adt_def.variants[0]
217+
}
218+
};
219+
let field_def = match field_name {
220+
NamedField(name) => variant_def.field_named(name),
221+
PositionalField(idx) => &variant_def.fields[idx]
222+
};
223+
(adt_def, field_def)
211224
}
212225

213-
pub fn get_field(&self, name: ast::Name) -> Option<DefId> {
226+
pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
214227
match self.cat {
215-
Categorization::Deref(ref cmt, ..) |
216-
Categorization::Interior(ref cmt, _) |
217-
Categorization::Downcast(ref cmt, _) => {
218-
if let Categorization::Local(_) = cmt.cat {
219-
if let ty::TyAdt(def, _) = self.ty.sty {
220-
if def.is_struct() {
221-
return def.struct_variant().find_field_named(name).map(|x| x.did);
228+
Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) |
229+
Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => {
230+
// try to figure out where the immutable reference came from
231+
match base_cmt.cat {
232+
Categorization::Local(node_id) =>
233+
Some(ImmutabilityBlame::LocalDeref(node_id)),
234+
Categorization::Interior(ref base_cmt, InteriorField(field_name)) => {
235+
let (adt_def, field_def) = base_cmt.resolve_field(field_name);
236+
Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def))
237+
}
238+
Categorization::Upvar(Upvar { id, .. }) => {
239+
if let NoteClosureEnv(..) = self.note {
240+
Some(ImmutabilityBlame::ClosureEnv(id.closure_expr_id))
241+
} else {
242+
None
222243
}
223244
}
224-
None
225-
} else {
226-
cmt.get_field(name)
245+
_ => None
227246
}
228247
}
229-
_ => None
230-
}
231-
}
232-
233-
pub fn get_field_name(&self) -> Option<ast::Name> {
234-
match self.cat {
235-
Categorization::Interior(_, ref ik) => {
236-
if let InteriorKind::InteriorField(FieldName::NamedField(name)) = *ik {
237-
Some(name)
238-
} else {
239-
None
240-
}
248+
Categorization::Local(node_id) => {
249+
Some(ImmutabilityBlame::ImmLocal(node_id))
241250
}
242-
Categorization::Deref(ref cmt, ..) |
243-
Categorization::Downcast(ref cmt, _) => {
244-
cmt.get_field_name()
251+
Categorization::Rvalue(..) |
252+
Categorization::Upvar(..) |
253+
Categorization::Deref(.., UnsafePtr(..)) => {
254+
// This should not be reachable up to inference limitations.
255+
None
245256
}
246-
_ => None,
247-
}
248-
}
249-
250-
pub fn get_arg_if_immutable(&self, map: &hir_map::Map) -> Option<ast::NodeId> {
251-
match self.cat {
252-
Categorization::Deref(ref cmt, ..) |
253-
Categorization::Interior(ref cmt, _) |
254-
Categorization::Downcast(ref cmt, _) => {
255-
if let Categorization::Local(nid) = cmt.cat {
256-
if let ty::TyAdt(_, _) = self.ty.sty {
257-
if let ty::TyRef(_, ty::TypeAndMut{mutbl: MutImmutable, ..}) = cmt.ty.sty {
258-
return Some(nid);
259-
}
260-
}
261-
None
262-
} else {
263-
cmt.get_arg_if_immutable(map)
264-
}
257+
Categorization::Interior(ref base_cmt, _) |
258+
Categorization::Downcast(ref base_cmt, _) |
259+
Categorization::Deref(ref base_cmt, _, _) => {
260+
base_cmt.immutability_blame()
261+
}
262+
Categorization::StaticItem => {
263+
// Do we want to do something here?
264+
None
265265
}
266-
_ => None
267266
}
268267
}
269268
}
@@ -1282,9 +1281,6 @@ pub enum Aliasability {
12821281
#[derive(Copy, Clone, Debug)]
12831282
pub enum AliasableReason {
12841283
AliasableBorrowed,
1285-
AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env
1286-
AliasableOther,
1287-
UnaliasableImmutable, // Created as needed upon seeing ImmutableUnique
12881284
AliasableStatic,
12891285
AliasableStaticMut,
12901286
}
@@ -1324,23 +1320,13 @@ impl<'tcx> cmt_<'tcx> {
13241320
Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) |
13251321
Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
13261322
Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
1323+
Categorization::Deref(ref b, _, Unique) |
13271324
Categorization::Downcast(ref b, _) |
13281325
Categorization::Interior(ref b, _) => {
13291326
// Aliasability depends on base cmt
13301327
b.freely_aliasable()
13311328
}
13321329

1333-
Categorization::Deref(ref b, _, Unique) => {
1334-
let sub = b.freely_aliasable();
1335-
if b.mutbl.is_mutable() {
1336-
// Aliasability depends on base cmt alone
1337-
sub
1338-
} else {
1339-
// Do not allow mutation through an immutable box.
1340-
ImmutableUnique(Box::new(sub))
1341-
}
1342-
}
1343-
13441330
Categorization::Rvalue(..) |
13451331
Categorization::Local(..) |
13461332
Categorization::Upvar(..) |
@@ -1356,13 +1342,9 @@ impl<'tcx> cmt_<'tcx> {
13561342
}
13571343
}
13581344

1359-
Categorization::Deref(ref base, _, BorrowedPtr(ty::ImmBorrow, _)) |
1360-
Categorization::Deref(ref base, _, Implicit(ty::ImmBorrow, _)) => {
1361-
match base.cat {
1362-
Categorization::Upvar(Upvar{ id, .. }) =>
1363-
FreelyAliasable(AliasableClosure(id.closure_expr_id)),
1364-
_ => FreelyAliasable(AliasableBorrowed)
1365-
}
1345+
Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
1346+
Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => {
1347+
FreelyAliasable(AliasableBorrowed)
13661348
}
13671349
}
13681350
}

‎src/librustc_borrowck/borrowck/gather_loans/mod.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,6 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
188188
// user knows what they're doing in these cases.
189189
Ok(())
190190
}
191-
(mc::Aliasability::ImmutableUnique(_), ty::MutBorrow) => {
192-
bccx.report_aliasability_violation(
193-
borrow_span,
194-
loan_cause,
195-
mc::AliasableReason::UnaliasableImmutable,
196-
cmt);
197-
Err(())
198-
}
199191
(mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) |
200192
(mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => {
201193
bccx.report_aliasability_violation(
@@ -510,4 +502,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
510502
self.move_error_collector.report_potential_errors(self.bccx);
511503
}
512504
}
513-

‎src/librustc_borrowck/borrowck/mod.rs

Lines changed: 116 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ use rustc::hir::def_id::DefId;
3434
use rustc::middle::expr_use_visitor as euv;
3535
use rustc::middle::mem_categorization as mc;
3636
use rustc::middle::mem_categorization::Categorization;
37+
use rustc::middle::mem_categorization::ImmutabilityBlame;
3738
use rustc::middle::region;
3839
use rustc::ty::{self, TyCtxt};
3940

4041
use std::fmt;
4142
use std::rc::Rc;
4243
use std::hash::{Hash, Hasher};
4344
use syntax::ast;
45+
use syntax::symbol::keywords;
4446
use syntax_pos::{MultiSpan, Span};
4547
use errors::DiagnosticBuilder;
4648

@@ -659,12 +661,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
659661
self.tcx.sess.span_err_with_code(s, msg, code);
660662
}
661663

662-
pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
664+
fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
663665
let span = err.span.clone();
664-
let mut immutable_field = None;
665-
let mut local_def = None;
666666

667-
let msg = &match err.code {
667+
let msg = match err.code {
668668
err_mutbl => {
669669
let descr = match err.cmt.note {
670670
mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => {
@@ -700,27 +700,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
700700
BorrowViolation(euv::AutoUnsafe) |
701701
BorrowViolation(euv::ForLoop) |
702702
BorrowViolation(euv::MatchDiscriminant) => {
703-
// Check for this field's definition to see if it is an immutable reference
704-
// and suggest making it mutable if that is the case.
705-
immutable_field = err.cmt.get_field_name()
706-
.and_then(|name| err.cmt.get_field(name))
707-
.and_then(|did| self.tcx.hir.as_local_node_id(did))
708-
.and_then(|nid| {
709-
if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(nid) {
710-
return self.suggest_mut_for_immutable(&field.ty)
711-
.map(|msg| (self.tcx.hir.span(nid), msg));
712-
}
713-
None
714-
});
715-
local_def = err.cmt.get_def()
716-
.and_then(|nid| {
717-
if !self.tcx.hir.is_argument(nid) {
718-
Some(self.tcx.hir.span(nid))
719-
} else {
720-
None
721-
}
722-
});
723-
724703
format!("cannot borrow {} as mutable", descr)
725704
}
726705
BorrowViolation(euv::ClosureInvocation) => {
@@ -746,16 +725,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
746725
}
747726
};
748727

749-
let mut db = self.struct_span_err(span, msg);
750-
if let Some((span, msg)) = immutable_field {
751-
db.span_label(span, &msg);
752-
}
753-
if let Some(let_span) = local_def {
754-
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
755-
db.span_label(let_span, &format!("consider changing this to `mut {}`", snippet));
756-
}
757-
}
758-
db
728+
self.struct_span_err(span, &msg)
759729
}
760730

761731
pub fn report_aliasability_violation(&self,
@@ -788,55 +758,49 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
788758
}
789759
};
790760

791-
let mut err = match cause {
792-
mc::AliasableOther => {
793-
struct_span_err!(
794-
self.tcx.sess, span, E0385,
795-
"{} in an aliasable location", prefix)
796-
}
797-
mc::AliasableReason::UnaliasableImmutable => {
798-
struct_span_err!(
799-
self.tcx.sess, span, E0386,
800-
"{} in an immutable container", prefix)
761+
match cause {
762+
mc::AliasableStatic |
763+
mc::AliasableStaticMut => {
764+
// This path cannot occur. It happens when we have an
765+
// `&mut` or assignment to a static. But in the case
766+
// of `static X`, we get a mutability violation first,
767+
// and never get here. In the case of `static mut X`,
768+
// that is unsafe and hence the aliasability error is
769+
// ignored.
770+
span_bug!(span, "aliasability violation for static `{}`", prefix)
801771
}
802-
mc::AliasableClosure(id) => {
772+
mc::AliasableBorrowed => {}
773+
};
774+
let blame = cmt.immutability_blame();
775+
let mut err = match blame {
776+
Some(ImmutabilityBlame::ClosureEnv(id)) => {
803777
let mut err = struct_span_err!(
804778
self.tcx.sess, span, E0387,
805779
"{} in a captured outer variable in an `Fn` closure", prefix);
806-
if let BorrowViolation(euv::ClosureCapture(_)) = kind {
780+
781+
// FIXME: the distinction between these 2 messages looks wrong.
782+
let help = if let BorrowViolation(euv::ClosureCapture(_)) = kind {
807783
// The aliasability violation with closure captures can
808784
// happen for nested closures, so we know the enclosing
809785
// closure incorrectly accepts an `Fn` while it needs to
810786
// be `FnMut`.
811-
span_help!(&mut err, self.tcx.hir.span(id),
812-
"consider changing this to accept closures that implement `FnMut`");
787+
"consider changing this to accept closures that implement `FnMut`"
788+
813789
} else {
814-
span_help!(&mut err, self.tcx.hir.span(id),
815-
"consider changing this closure to take self by mutable reference");
816-
}
790+
"consider changing this closure to take self by mutable reference"
791+
};
792+
err.span_help(self.tcx.hir.span(id), help);
817793
err
818794
}
819-
mc::AliasableStatic |
820-
mc::AliasableStaticMut => {
821-
// This path cannot occur. It happens when we have an
822-
// `&mut` or assignment to a static. But in the case
823-
// of `static X`, we get a mutability violation first,
824-
// and never get here. In the case of `static mut X`,
825-
// that is unsafe and hence the aliasability error is
826-
// ignored.
827-
span_bug!(span, "aliasability violation for static `{}`", prefix)
828-
}
829-
mc::AliasableBorrowed => {
830-
let mut e = struct_span_err!(
795+
_ => {
796+
let mut err = struct_span_err!(
831797
self.tcx.sess, span, E0389,
832798
"{} in a `&` reference", prefix);
833-
e.span_label(span, &"assignment into an immutable reference");
834-
if let Some(nid) = cmt.get_arg_if_immutable(&self.tcx.hir) {
835-
self.immutable_argument_should_be_mut(nid, &mut e);
836-
}
837-
e
799+
err.span_label(span, &"assignment into an immutable reference");
800+
err
838801
}
839802
};
803+
self.note_immutability_blame(&mut err, blame);
840804

841805
if is_closure {
842806
err.help("closures behind references must be called via `&mut`");
@@ -873,21 +837,93 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
873837
None
874838
}
875839

876-
fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) {
877-
let parent = self.tcx.hir.get_parent_node(nid);
840+
fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode {
841+
let pat = match self.tcx.hir.get(node_id) {
842+
hir_map::Node::NodeLocal(pat) => pat,
843+
node => bug!("bad node for local: {:?}", node)
844+
};
845+
846+
match pat.node {
847+
hir::PatKind::Binding(mode, ..) => mode,
848+
_ => bug!("local is not a binding: {:?}", pat)
849+
}
850+
}
851+
852+
fn local_ty(&self, node_id: ast::NodeId) -> Option<&hir::Ty> {
853+
let parent = self.tcx.hir.get_parent_node(node_id);
878854
let parent_node = self.tcx.hir.get(parent);
879855

880856
// The parent node is like a fn
881857
if let Some(fn_like) = FnLikeNode::from_node(parent_node) {
882858
// `nid`'s parent's `Body`
883859
let fn_body = self.tcx.hir.body(fn_like.body());
884860
// Get the position of `nid` in the arguments list
885-
let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == nid);
861+
let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id);
886862
if let Some(i) = arg_pos {
887863
// The argument's `Ty`
888-
let arg_ty = &fn_like.decl().inputs[i];
889-
if let Some(msg) = self.suggest_mut_for_immutable(&arg_ty) {
890-
db.span_label(arg_ty.span, &msg);
864+
Some(&fn_like.decl().inputs[i])
865+
} else {
866+
None
867+
}
868+
} else {
869+
None
870+
}
871+
}
872+
873+
fn note_immutability_blame(&self,
874+
db: &mut DiagnosticBuilder,
875+
blame: Option<ImmutabilityBlame>) {
876+
match blame {
877+
None => {}
878+
Some(ImmutabilityBlame::ClosureEnv(_)) => {}
879+
Some(ImmutabilityBlame::ImmLocal(node_id)) => {
880+
let let_span = self.tcx.hir.span(node_id);
881+
if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) {
882+
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
883+
if self.tcx.hir.name(node_id) == keywords::SelfValue.name() &&
884+
snippet != "self" {
885+
// avoid suggesting `mut &self`.
886+
return
887+
}
888+
db.span_label(
889+
let_span,
890+
&format!("consider changing this to `mut {}`", snippet)
891+
);
892+
}
893+
}
894+
}
895+
Some(ImmutabilityBlame::LocalDeref(node_id)) => {
896+
let let_span = self.tcx.hir.span(node_id);
897+
match self.local_binding_mode(node_id) {
898+
hir::BindingMode::BindByRef(..) => {
899+
let snippet = self.tcx.sess.codemap().span_to_snippet(let_span);
900+
if let Ok(snippet) = snippet {
901+
db.span_label(
902+
let_span,
903+
&format!("consider changing this to `{}`",
904+
snippet.replace("ref ", "ref mut "))
905+
);
906+
}
907+
}
908+
hir::BindingMode::BindByValue(..) => {
909+
if let Some(local_ty) = self.local_ty(node_id) {
910+
if let Some(msg) = self.suggest_mut_for_immutable(local_ty) {
911+
db.span_label(local_ty.span, &msg);
912+
}
913+
}
914+
}
915+
}
916+
}
917+
Some(ImmutabilityBlame::AdtFieldDeref(_, field)) => {
918+
let node_id = match self.tcx.hir.as_local_node_id(field.did) {
919+
Some(node_id) => node_id,
920+
None => return
921+
};
922+
923+
if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) {
924+
if let Some(msg) = self.suggest_mut_for_immutable(&field.ty) {
925+
db.span_label(field.ty.span, &msg);
926+
}
891927
}
892928
}
893929
}
@@ -941,10 +977,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
941977
}
942978
}
943979

944-
pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) {
980+
fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) {
945981
let error_span = err.span.clone();
946982
match err.code {
947-
err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span),
983+
err_mutbl => {
984+
self.note_and_explain_mutbl_error(db, &err, &error_span);
985+
self.note_immutability_blame(db, err.cmt.immutability_blame());
986+
}
948987
err_out_of_scope(super_scope, sub_scope, cause) => {
949988
let (value_kind, value_msg) = match err.cmt.cat {
950989
mc::Categorization::Rvalue(..) =>
@@ -1096,28 +1135,13 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \
10961135
_ => {
10971136
if let Categorization::Deref(..) = err.cmt.cat {
10981137
db.span_label(*error_span, &"cannot borrow as mutable");
1099-
if let Some(local_id) = err.cmt.get_arg_if_immutable(&self.tcx.hir) {
1100-
self.immutable_argument_should_be_mut(local_id, db);
1101-
} else if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
1102-
if let Categorization::Local(local_id) = inner_cmt.cat {
1103-
self.immutable_argument_should_be_mut(local_id, db);
1104-
}
1105-
}
11061138
} else if let Categorization::Local(local_id) = err.cmt.cat {
11071139
let span = self.tcx.hir.span(local_id);
11081140
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
11091141
if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") {
11101142
db.span_label(*error_span, &format!("cannot reborrow mutably"));
11111143
db.span_label(*error_span, &format!("try removing `&mut` here"));
11121144
} else {
1113-
if snippet.starts_with("ref ") {
1114-
db.span_label(span, &format!("use `{}` here to make mutable",
1115-
snippet.replace("ref ", "ref mut ")));
1116-
} else if snippet != "self" {
1117-
db.span_label(span,
1118-
&format!("use `mut {}` here to make mutable",
1119-
snippet));
1120-
}
11211145
db.span_label(*error_span, &format!("cannot borrow mutably"));
11221146
}
11231147
} else {

‎src/librustc_borrowck/diagnostics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ fn main() {
198198
```
199199
"##,
200200

201-
E0386: r##"
201+
/*E0386: r##"
202202
This error occurs when an attempt is made to mutate the target of a mutable
203203
reference stored inside an immutable container.
204204
@@ -228,7 +228,7 @@ let x: i64 = 1;
228228
let y: Box<Cell<_>> = Box::new(Cell::new(x));
229229
y.set(2);
230230
```
231-
"##,
231+
"##,*/
232232

233233
E0387: r##"
234234
This error occurs when an attempt is made to mutate or mutably reference data
@@ -1117,6 +1117,6 @@ fn main() {
11171117
}
11181118

11191119
register_diagnostics! {
1120-
E0385, // {} in an aliasable location
1120+
// E0385, // {} in an aliasable location
11211121
E0524, // two closures require unique access to `..` at the same time
11221122
}

‎src/test/compile-fail/augmented-assignments.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fn main() {
2727
x; //~ value moved here
2828

2929
let y = Int(2);
30-
//~^use `mut y` here to make mutable
30+
//~^ consider changing this to `mut y`
3131
y //~ error: cannot borrow immutable local variable `y` as mutable
3232
//~| cannot borrow
3333
+=

‎src/test/compile-fail/borrowck/borrowck-issue-14498.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ fn indirect_write_to_imm_box() {
2323
let mut x: isize = 1;
2424
let y: Box<_> = box &mut x;
2525
let p = &y;
26-
***p = 2; //~ ERROR cannot assign to data in an immutable container
26+
***p = 2; //~ ERROR cannot assign to data in a `&` reference
2727
drop(p);
2828
}
2929

@@ -43,7 +43,6 @@ fn borrow_in_var_from_var_via_imm_box() {
4343
let p = &y;
4444
let q = &***p;
4545
**y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
46-
//~^ ERROR cannot assign to data in an immutable container
4746
drop(p);
4847
drop(q);
4948
}
@@ -64,7 +63,6 @@ fn borrow_in_var_from_field_via_imm_box() {
6463
let p = &y;
6564
let q = &***p;
6665
**y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
67-
//~^ ERROR cannot assign to data in an immutable container
6866
drop(p);
6967
drop(q);
7068
}
@@ -85,7 +83,6 @@ fn borrow_in_field_from_var_via_imm_box() {
8583
let p = &y.a;
8684
let q = &***p;
8785
**y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
88-
//~^ ERROR cannot assign to data in an immutable container
8986
drop(p);
9087
drop(q);
9188
}
@@ -106,7 +103,6 @@ fn borrow_in_field_from_field_via_imm_box() {
106103
let p = &y.a;
107104
let q = &***p;
108105
**y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
109-
//~^ ERROR cannot assign to data in an immutable container
110106
drop(p);
111107
drop(q);
112108
}

‎src/test/compile-fail/issue-33819.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fn main() {
1212
match op {
1313
Some(ref v) => { let a = &mut v; },
1414
//~^ ERROR:cannot borrow immutable
15-
//~| use `ref mut v` here to make mutable
15+
//~| cannot borrow mutably
1616
None => {},
1717
}
1818
}

‎src/test/compile-fail/mut-suggestion.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ impl S {
1717
}
1818

1919
fn func(arg: S) {
20-
//~^ here to make mutable
20+
//~^ consider changing this to `mut arg`
2121
arg.mutate();
2222
//~^ ERROR cannot borrow immutable argument
2323
//~| cannot borrow mutably
2424
}
2525

2626
fn main() {
2727
let local = S;
28-
//~^ here to make mutable
28+
//~^ consider changing this to `mut local`
2929
local.mutate();
3030
//~^ ERROR cannot borrow immutable local variable
3131
//~| cannot borrow mutably

‎src/test/ui/codemap_tests/huge_multispan_highlight.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: cannot borrow immutable local variable `x` as mutable
22
--> $DIR/huge_multispan_highlight.rs:100:18
33
|
44
12 | let x = "foo";
5-
| - use `mut x` here to make mutable
5+
| - consider changing this to `mut x`
66
...
77
100 | let y = &mut x;
88
| ^ cannot borrow mutably

‎src/test/ui/did_you_mean/issue-31424.stderr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ error: cannot borrow immutable argument `self` as mutable
1010
error: cannot borrow immutable argument `self` as mutable
1111
--> $DIR/issue-31424.rs:23:15
1212
|
13+
22 | fn bar(self: &mut Self) {
14+
| ---- consider changing this to `mut self`
1315
23 | (&mut self).bar();
1416
| ^^^^ cannot borrow mutably
1517

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct Foo {
12+
pub v: Vec<String>
13+
}
14+
15+
fn main() {
16+
let f = Foo { v: Vec::new() };
17+
f.v.push("cat".to_string());
18+
}
19+
20+
21+
struct S {
22+
x: i32,
23+
}
24+
fn foo() {
25+
let s = S { x: 42 };
26+
s.x += 1;
27+
}
28+
29+
fn bar(s: S) {
30+
s.x += 1;
31+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: cannot borrow immutable field `f.v` as mutable
2+
--> $DIR/issue-35937.rs:17:5
3+
|
4+
16 | let f = Foo { v: Vec::new() };
5+
| - consider changing this to `mut f`
6+
17 | f.v.push("cat".to_string());
7+
| ^^^ cannot mutably borrow immutable field
8+
9+
error: cannot assign to immutable field `s.x`
10+
--> $DIR/issue-35937.rs:26:5
11+
|
12+
25 | let s = S { x: 42 };
13+
| - consider changing this to `mut s`
14+
26 | s.x += 1;
15+
| ^^^^^^^^ cannot mutably borrow immutable field
16+
17+
error: cannot assign to immutable field `s.x`
18+
--> $DIR/issue-35937.rs:30:5
19+
|
20+
29 | fn bar(s: S) {
21+
| - consider changing this to `mut s`
22+
30 | s.x += 1;
23+
| ^^^^^^^^ cannot mutably borrow immutable field
24+
25+
error: aborting due to 3 previous errors
26+

‎src/test/ui/did_you_mean/issue-38147-2.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable
22
--> $DIR/issue-38147-2.rs:17:9
33
|
44
12 | s: &'a String
5-
| ------------- use `&'a mut String` here to make mutable
5+
| ---------- use `&'a mut String` here to make mutable
66
...
77
17 | self.s.push('x');
88
| ^^^^^^ cannot borrow as mutable

‎src/test/ui/did_you_mean/issue-38147-3.stderr

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable
22
--> $DIR/issue-38147-3.rs:17:9
33
|
44
12 | s: &'a String
5-
| ------------- use `&'a mut String` here to make mutable
5+
| ---------- use `&'a mut String` here to make mutable
66
...
7-
16 | fn f(&self) {
8-
| ----- use `&mut self` here to make mutable
97
17 | self.s.push('x');
108
| ^^^^^^ cannot borrow as mutable
119

‎src/test/ui/did_you_mean/issue-39544.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,20 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
enum X {
11+
pub enum X {
1212
Y
1313
}
1414

15-
struct Z {
15+
pub struct Z {
1616
x: X
1717
}
1818

19-
fn main() {
19+
pub fn main() {
2020
let z = Z { x: X::Y };
2121
let _ = &mut z.x;
2222
}
23+
24+
pub fn with_arg(z: Z, w: &Z) {
25+
let _ = &mut z.x;
26+
let _ = &mut w.x;
27+
}

‎src/test/ui/did_you_mean/issue-39544.stderr

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,22 @@ error: cannot borrow immutable field `z.x` as mutable
66
21 | let _ = &mut z.x;
77
| ^^^ cannot mutably borrow immutable field
88

9-
error: aborting due to previous error
9+
error: cannot borrow immutable field `z.x` as mutable
10+
--> $DIR/issue-39544.rs:25:18
11+
|
12+
24 | pub fn with_arg(z: Z, w: &Z) {
13+
| - consider changing this to `mut z`
14+
25 | let _ = &mut z.x;
15+
| ^^^ cannot mutably borrow immutable field
16+
17+
error: cannot borrow immutable field `w.x` as mutable
18+
--> $DIR/issue-39544.rs:26:18
19+
|
20+
24 | pub fn with_arg(z: Z, w: &Z) {
21+
| -- use `&mut Z` here to make mutable
22+
25 | let _ = &mut z.x;
23+
26 | let _ = &mut w.x;
24+
| ^^^ cannot mutably borrow immutable field
25+
26+
error: aborting due to 3 previous errors
1027

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let mut buf = &[1, 2, 3, 4];
13+
buf.iter_mut();
14+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: cannot borrow immutable borrowed content `*buf` as mutable
2+
--> $DIR/issue-40823.rs:13:5
3+
|
4+
13 | buf.iter_mut();
5+
| ^^^ cannot borrow as mutable
6+
7+
error: aborting due to previous error
8+

‎src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: cannot borrow immutable argument `x` as mutable
22
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24
33
|
44
62 | fn deref_mut_field1(x: Own<Point>) {
5-
| - use `mut x` here to make mutable
5+
| - consider changing this to `mut x`
66
63 | let __isize = &mut x.y; //~ ERROR cannot borrow
77
| ^ cannot borrow mutably
88

@@ -28,7 +28,7 @@ error: cannot borrow immutable argument `x` as mutable
2828
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5
2929
|
3030
97 | fn assign_field1<'a>(x: Own<Point>) {
31-
| - use `mut x` here to make mutable
31+
| - consider changing this to `mut x`
3232
98 | x.y = 3; //~ ERROR cannot borrow
3333
| ^ cannot borrow mutably
3434

@@ -54,7 +54,7 @@ error: cannot borrow immutable argument `x` as mutable
5454
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5
5555
|
5656
118 | fn deref_mut_method1(x: Own<Point>) {
57-
| - use `mut x` here to make mutable
57+
| - consider changing this to `mut x`
5858
119 | x.set(0, 0); //~ ERROR cannot borrow
5959
| ^ cannot borrow mutably
6060

@@ -70,7 +70,7 @@ error: cannot borrow immutable argument `x` as mutable
7070
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6
7171
|
7272
138 | fn assign_method1<'a>(x: Own<Point>) {
73-
| - use `mut x` here to make mutable
73+
| - consider changing this to `mut x`
7474
139 | *x.y_mut() = 3; //~ ERROR cannot borrow
7575
| ^ cannot borrow mutably
7676

‎src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: cannot borrow immutable argument `x` as mutable
22
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25
33
|
44
38 | fn deref_mut1(x: Own<isize>) {
5-
| - use `mut x` here to make mutable
5+
| - consider changing this to `mut x`
66
39 | let __isize = &mut *x; //~ ERROR cannot borrow
77
| ^ cannot borrow mutably
88

@@ -18,7 +18,7 @@ error: cannot borrow immutable argument `x` as mutable
1818
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6
1919
|
2020
58 | fn assign1<'a>(x: Own<isize>) {
21-
| - use `mut x` here to make mutable
21+
| - consider changing this to `mut x`
2222
59 | *x = 3; //~ ERROR cannot borrow
2323
| ^ cannot borrow mutably
2424

‎src/test/ui/span/borrowck-object-mutability.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ error: cannot borrow immutable borrowed content `*x` as mutable
1010
error: cannot borrow immutable `Box` content `*x` as mutable
1111
--> $DIR/borrowck-object-mutability.rs:29:5
1212
|
13+
27 | fn owned_receiver(x: Box<Foo>) {
14+
| - consider changing this to `mut x`
15+
28 | x.borrowed();
1316
29 | x.borrowed_mut(); //~ ERROR cannot borrow
1417
| ^ cannot borrow as mutable
1518

0 commit comments

Comments
 (0)
Please sign in to comment.