diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 2ac1a036f99e1..726c305e90304 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -907,6 +907,13 @@ impl<'a> LoweringContext<'a> {
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
},
variadic: decl.variadic,
+ has_implicit_self: decl.inputs.get(0).map_or(false, |arg| {
+ match arg.ty.node {
+ TyKind::ImplicitSelf => true,
+ TyKind::Rptr(_, ref mt) => mt.ty.node == TyKind::ImplicitSelf,
+ _ => false
+ }
+ })
})
}
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 1c79a02d3da0e..43b7deb5b90e3 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1379,6 +1379,9 @@ pub struct FnDecl {
pub inputs: HirVec
>,
pub output: FunctionRetTy,
pub variadic: bool,
+ /// True if this function has an `self`, `&self` or `&mut self` receiver
+ /// (but not a `self: Xxx` one).
+ pub has_implicit_self: bool,
}
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 0cf53826dd427..3b52e85e08e32 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -194,76 +194,75 @@ pub struct cmt_<'tcx> {
pub type cmt<'tcx> = Rc>;
+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 {
- 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 {
+ pub fn immutability_blame(&self) -> Option> {
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 {
- 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 {
- 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)
}
}
}
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 28b6c7a13f171..cedb9e1cd1cff 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -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);
}
}
-
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 20d495976b05f..558a835be1884 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -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};
@@ -659,12 +660,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 +699,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 +724,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,55 +757,49 @@ 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)
+ match cause {
+ mc::AliasableStatic |
+ mc::AliasableStaticMut => {
+ // This path cannot occur. It happens when we have an
+ // `&mut` or assignment to a static. But in the case
+ // of `static X`, we get a mutability violation first,
+ // and never get here. In the case of `static mut X`,
+ // that is unsafe and hence the aliasability error is
+ // ignored.
+ span_bug!(span, "aliasability violation for static `{}`", prefix)
}
- mc::AliasableClosure(id) => {
+ 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);
- if let BorrowViolation(euv::ClosureCapture(_)) = kind {
+
+ // 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`.
- span_help!(&mut err, self.tcx.hir.span(id),
- "consider changing this to accept closures that implement `FnMut`");
+ "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");
- }
+ "consider changing this closure to take self by mutable reference"
+ };
+ err.span_help(self.tcx.hir.span(id), help);
err
}
- mc::AliasableStatic |
- mc::AliasableStaticMut => {
- // This path cannot occur. It happens when we have an
- // `&mut` or assignment to a static. But in the case
- // of `static X`, we get a mutability violation first,
- // and never get here. In the case of `static mut X`,
- // that is unsafe and hence the aliasability error is
- // ignored.
- span_bug!(span, "aliasability violation for static `{}`", prefix)
- }
- mc::AliasableBorrowed => {
- let mut e = struct_span_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`");
@@ -845,49 +808,124 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
/// Given a type, if it is an immutable reference, return a suggestion to make it mutable
- fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option {
+ fn suggest_mut_for_immutable(&self, pty: &hir::Ty, is_implicit_self: bool) -> Option {
// Check wether the argument is an immutable reference
+ debug!("suggest_mut_for_immutable({:?}, {:?})", pty, is_implicit_self);
if let hir::TyRptr(lifetime, hir::MutTy {
mutbl: hir::Mutability::MutImmutable,
ref ty
}) = pty.node {
// Account for existing lifetimes when generating the message
- if !lifetime.is_elided() {
- 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) {
- return Some(format!("use `&{} mut {}` here to make mutable",
- lifetime_snippet,
- snippet));
- }
- }
- } else if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(pty.span) {
- if snippet.starts_with("&") {
- return Some(format!("use `{}` here to make mutable",
- snippet.replace("&", "&mut ")));
- }
+ let pointee_snippet = match self.tcx.sess.codemap().span_to_snippet(ty.span) {
+ Ok(snippet) => snippet,
+ _ => return None
+ };
+
+ let lifetime_snippet = if !lifetime.is_elided() {
+ format!("{} ", match self.tcx.sess.codemap().span_to_snippet(lifetime.span) {
+ Ok(lifetime_snippet) => lifetime_snippet,
+ _ => return None
+ })
} else {
- bug!("couldn't find a snippet for span: {:?}", pty.span);
- }
+ String::new()
+ };
+ Some(format!("use `&{}mut {}` here to make mutable",
+ lifetime_snippet,
+ if is_implicit_self { "self" } else { &*pointee_snippet }))
+ } else {
+ None
}
- 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>, bool) {
+ 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
if let Some(fn_like) = FnLikeNode::from_node(parent_node) {
// `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);
+ // Get the position of `node_id` in the arguments list
+ 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]),
+ i == 0 && fn_like.decl().has_implicit_self)
+ } else {
+ (None, false)
+ }
+ } else {
+ (None, false)
+ }
+ }
+
+ fn note_immutability_blame(&self,
+ db: &mut DiagnosticBuilder,
+ blame: Option) {
+ 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) {
+ let (_, is_implicit_self) = self.local_ty(node_id);
+ if is_implicit_self && 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), is_implicit_self) = self.local_ty(node_id) {
+ if let Some(msg) =
+ self.suggest_mut_for_immutable(local_ty, is_implicit_self) {
+ 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, false) {
+ db.span_label(field.ty.span, &msg);
+ }
}
}
}
@@ -941,10 +979,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 +1137,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 +1144,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 {
diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs
index db4a1701e976b..bfd342a9f2134 100644
--- a/src/librustc_borrowck/diagnostics.rs
+++ b/src/librustc_borrowck/diagnostics.rs
@@ -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> = 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
}
diff --git a/src/test/compile-fail/augmented-assignments.rs b/src/test/compile-fail/augmented-assignments.rs
index 92a8b10669cee..736aa465aa732 100644
--- a/src/test/compile-fail/augmented-assignments.rs
+++ b/src/test/compile-fail/augmented-assignments.rs
@@ -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
+=
diff --git a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs
index 64033623fe2d1..8b7ccedd6974f 100644
--- a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs
+++ b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs
@@ -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);
}
diff --git a/src/test/compile-fail/issue-33819.rs b/src/test/compile-fail/issue-33819.rs
index 9c9677c1e9863..499e7e54947b7 100644
--- a/src/test/compile-fail/issue-33819.rs
+++ b/src/test/compile-fail/issue-33819.rs
@@ -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 => {},
}
}
diff --git a/src/test/compile-fail/mut-suggestion.rs b/src/test/compile-fail/mut-suggestion.rs
index 242ad7aee8d12..0015c8e5c00a1 100644
--- a/src/test/compile-fail/mut-suggestion.rs
+++ b/src/test/compile-fail/mut-suggestion.rs
@@ -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
diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr
index edbfd72df615f..7bb69caa1024a 100644
--- a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr
+++ b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr
@@ -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
diff --git a/src/test/ui/did_you_mean/issue-31424.stderr b/src/test/ui/did_you_mean/issue-31424.stderr
index 4873acf551ebc..60fa06d314ff7 100644
--- a/src/test/ui/did_you_mean/issue-31424.stderr
+++ b/src/test/ui/did_you_mean/issue-31424.stderr
@@ -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
diff --git a/src/test/ui/did_you_mean/issue-35937.rs b/src/test/ui/did_you_mean/issue-35937.rs
new file mode 100644
index 0000000000000..9ec8728fd32c1
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-35937.rs
@@ -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 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo {
+ pub v: Vec
+}
+
+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;
+}
diff --git a/src/test/ui/did_you_mean/issue-35937.stderr b/src/test/ui/did_you_mean/issue-35937.stderr
new file mode 100644
index 0000000000000..bea3d1291433d
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-35937.stderr
@@ -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
+
diff --git a/src/test/ui/did_you_mean/issue-38147-2.stderr b/src/test/ui/did_you_mean/issue-38147-2.stderr
index fdaf0cd44d9d4..855feaf7d2d5e 100644
--- a/src/test/ui/did_you_mean/issue-38147-2.stderr
+++ b/src/test/ui/did_you_mean/issue-38147-2.stderr
@@ -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
diff --git a/src/test/ui/did_you_mean/issue-38147-3.stderr b/src/test/ui/did_you_mean/issue-38147-3.stderr
index d2280fa561bde..d970d078df8d9 100644
--- a/src/test/ui/did_you_mean/issue-38147-3.stderr
+++ b/src/test/ui/did_you_mean/issue-38147-3.stderr
@@ -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
diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs
index bcdafefa2472b..6331fc5771fcb 100644
--- a/src/test/ui/did_you_mean/issue-39544.rs
+++ b/src/test/ui/did_you_mean/issue-39544.rs
@@ -8,11 +8,11 @@
// 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
}
@@ -20,3 +20,34 @@ fn main() {
let z = Z { x: X::Y };
let _ = &mut z.x;
}
+
+impl Z {
+ fn foo<'z>(&'z self) {
+ let _ = &mut self.x;
+ }
+
+ fn foo1(&self, other: &Z) {
+ let _ = &mut self.x;
+ let _ = &mut other.x;
+ }
+
+ fn foo2<'a>(&'a self, other: &Z) {
+ let _ = &mut self.x;
+ let _ = &mut other.x;
+ }
+
+ fn foo3<'a>(self: &'a Self, other: &Z) {
+ let _ = &mut self.x;
+ let _ = &mut other.x;
+ }
+
+ fn foo4(other: &Z) {
+ let _ = &mut other.x;
+ }
+
+}
+
+pub fn with_arg(z: Z, w: &Z) {
+ let _ = &mut z.x;
+ let _ = &mut w.x;
+}
diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr
index 7f124e6d34d35..e1e229a8b0572 100644
--- a/src/test/ui/did_you_mean/issue-39544.stderr
+++ b/src/test/ui/did_you_mean/issue-39544.stderr
@@ -6,5 +6,89 @@ 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 `self.x` as mutable
+ --> $DIR/issue-39544.rs:26:22
+ |
+25 | fn foo<'z>(&'z self) {
+ | -------- use `&'z mut self` here to make mutable
+26 | let _ = &mut self.x;
+ | ^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `self.x` as mutable
+ --> $DIR/issue-39544.rs:30:22
+ |
+29 | fn foo1(&self, other: &Z) {
+ | ----- use `&mut self` here to make mutable
+30 | let _ = &mut self.x;
+ | ^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `other.x` as mutable
+ --> $DIR/issue-39544.rs:31:22
+ |
+29 | fn foo1(&self, other: &Z) {
+ | -- use `&mut Z` here to make mutable
+30 | let _ = &mut self.x;
+31 | let _ = &mut other.x;
+ | ^^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `self.x` as mutable
+ --> $DIR/issue-39544.rs:35:22
+ |
+34 | fn foo2<'a>(&'a self, other: &Z) {
+ | -------- use `&'a mut self` here to make mutable
+35 | let _ = &mut self.x;
+ | ^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `other.x` as mutable
+ --> $DIR/issue-39544.rs:36:22
+ |
+34 | fn foo2<'a>(&'a self, other: &Z) {
+ | -- use `&mut Z` here to make mutable
+35 | let _ = &mut self.x;
+36 | let _ = &mut other.x;
+ | ^^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `self.x` as mutable
+ --> $DIR/issue-39544.rs:40:22
+ |
+39 | fn foo3<'a>(self: &'a Self, other: &Z) {
+ | -------- use `&'a mut Self` here to make mutable
+40 | let _ = &mut self.x;
+ | ^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `other.x` as mutable
+ --> $DIR/issue-39544.rs:41:22
+ |
+39 | fn foo3<'a>(self: &'a Self, other: &Z) {
+ | -- use `&mut Z` here to make mutable
+40 | let _ = &mut self.x;
+41 | let _ = &mut other.x;
+ | ^^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `other.x` as mutable
+ --> $DIR/issue-39544.rs:45:22
+ |
+44 | fn foo4(other: &Z) {
+ | -- use `&mut Z` here to make mutable
+45 | let _ = &mut other.x;
+ | ^^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `z.x` as mutable
+ --> $DIR/issue-39544.rs:51:18
+ |
+50 | pub fn with_arg(z: Z, w: &Z) {
+ | - consider changing this to `mut z`
+51 | let _ = &mut z.x;
+ | ^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `w.x` as mutable
+ --> $DIR/issue-39544.rs:52:18
+ |
+50 | pub fn with_arg(z: Z, w: &Z) {
+ | -- use `&mut Z` here to make mutable
+51 | let _ = &mut z.x;
+52 | let _ = &mut w.x;
+ | ^^^ cannot mutably borrow immutable field
+
+error: aborting due to 11 previous errors
diff --git a/src/test/ui/did_you_mean/issue-40823.rs b/src/test/ui/did_you_mean/issue-40823.rs
new file mode 100644
index 0000000000000..f4ae325727982
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-40823.rs
@@ -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 or the MIT license
+// , 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();
+}
diff --git a/src/test/ui/did_you_mean/issue-40823.stderr b/src/test/ui/did_you_mean/issue-40823.stderr
new file mode 100644
index 0000000000000..8e77ebd9b6da3
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-40823.stderr
@@ -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
+
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
index b83a6aaebf323..edf1635a6b84f 100644
--- a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr
+++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr
@@ -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) {
- | - 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) {
- | - 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) {
- | - 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) {
- | - use `mut x` here to make mutable
+ | - consider changing this to `mut x`
139 | *x.y_mut() = 3; //~ ERROR cannot borrow
| ^ cannot borrow mutably
diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
index af954a4d7924f..2ec0116872179 100644
--- a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
+++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
@@ -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) {
- | - 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) {
- | - use `mut x` here to make mutable
+ | - consider changing this to `mut x`
59 | *x = 3; //~ ERROR cannot borrow
| ^ cannot borrow mutably
diff --git a/src/test/ui/span/borrowck-object-mutability.stderr b/src/test/ui/span/borrowck-object-mutability.stderr
index 4ef1cb9c239e4..0abdbdc3a21b5 100644
--- a/src/test/ui/span/borrowck-object-mutability.stderr
+++ b/src/test/ui/span/borrowck-object-mutability.stderr
@@ -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) {
+ | - consider changing this to `mut x`
+28 | x.borrowed();
29 | x.borrowed_mut(); //~ ERROR cannot borrow
| ^ cannot borrow as mutable
|