Fix #53466.
place: &str,
borrow_place: &str,
value_place: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
self.infcx.tcx.sess.create_err(crate::session_diagnostics::MoveBorrow {
place,
span,
desc: &str,
borrow_span: Span,
borrow_desc: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
span,
old_loan_span: Span,
old_opt_via: &str,
old_load_end_span: Option<Span>,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let via =
|msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) };
let mut err = struct_span_err!(
desc: &str,
old_loan_span: Span,
old_load_end_span: Option<Span>,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
new_loan_span,
&self,
span: Span,
desc: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
}
span: Span,
path: &str,
reason: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,)
}
immutable_place: &str,
immutable_section: &str,
action: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
mutate_span,
&self,
span: Span,
yield_span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
span,
pub(crate) fn cannot_borrow_across_destructor(
&self,
borrow_span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(
self,
borrow_span,
&self,
span: Span,
path: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0597, "{} does not live long enough", path,)
}
return_kind: &str,
reference_desc: &str,
path_desc: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
span,
closure_kind: &str,
borrowed_path: &str,
capture_span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
closure_span,
pub(crate) fn thread_local_value_does_not_live_long_enough(
&self,
span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",)
}
pub(crate) fn temporary_value_borrowed_for_too_long(
&self,
span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",)
}
// the verbs used in some diagnostic messages.
let act;
let acted_on;
+ let mut suggest = true;
+ let mut mut_error = None;
+ let mut count = 1;
let span = match error_access {
AccessKind::Mutate => {
let borrow_spans = self.borrow_spans(span, location);
let borrow_span = borrow_spans.args_or_use();
- err = self.cannot_borrow_path_as_mutable_because(borrow_span, &item_msg, &reason);
- borrow_spans.var_span_label(
- &mut err,
- format!(
- "mutable borrow occurs due to use of {} in closure",
- self.describe_any_place(access_place.as_ref()),
- ),
- "mutable",
- );
+ match the_place_err {
+ PlaceRef { local, projection: [] }
+ if self.body.local_decls[local].can_be_made_mutable() =>
+ {
+ let span = self.body.local_decls[local].source_info.span;
+ mut_error = Some(span);
+ if let Some((buffer, c)) = self.get_buffered_mut_error(span) {
+ // We've encountered a second (or more) attempt to mutably borrow an
+ // immutable binding, so the likely problem is with the binding
+ // declaration, not the use. We collect these in a single diagnostic
+ // and make the binding the primary span of the error.
+ err = buffer;
+ count = c + 1;
+ if count == 2 {
+ err.replace_span_with(span, false);
+ err.span_label(span, "not mutable");
+ }
+ suggest = false;
+ } else {
+ err = self.cannot_borrow_path_as_mutable_because(
+ borrow_span,
+ &item_msg,
+ &reason,
+ );
+ }
+ }
+ _ => {
+ err = self.cannot_borrow_path_as_mutable_because(
+ borrow_span,
+ &item_msg,
+ &reason,
+ );
+ }
+ }
+ if suggest {
+ borrow_spans.var_span_label(
+ &mut err,
+ format!(
+ "mutable borrow occurs due to use of {} in closure",
+ self.describe_any_place(access_place.as_ref()),
+ ),
+ "mutable",
+ );
+ }
borrow_span
}
};
pat_span: _,
},
)))) => {
- err.span_note(sp, "the binding is already a mutable borrow");
+ if suggest {
+ err.span_note(sp, "the binding is already a mutable borrow");
+ }
}
_ => {
err.span_note(
let local_decl = &self.body.local_decls[local];
assert_eq!(local_decl.mutability, Mutability::Not);
- err.span_label(span, format!("cannot {act}"));
- err.span_suggestion(
- local_decl.source_info.span,
- "consider changing this to be mutable",
- format!("mut {}", self.local_names[local].unwrap()),
- Applicability::MachineApplicable,
- );
- let tcx = self.infcx.tcx;
- if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
- self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+ if count < 10 {
+ err.span_label(span, format!("cannot {act}"));
+ }
+ if suggest {
+ err.span_suggestion(
+ local_decl.source_info.span,
+ "consider changing this to be mutable",
+ format!("mut {}", self.local_names[local].unwrap()),
+ Applicability::MachineApplicable,
+ );
+ let tcx = self.infcx.tcx;
+ if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
+ self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+ }
}
}
}
}
- self.buffer_error(err);
+ if let Some(span) = mut_error {
+ self.buffer_mut_error(span, err, count);
+ } else {
+ self.buffer_error(err);
+ }
}
fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
/// same primary span come out in a consistent order.
buffered_move_errors:
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>,
+ buffered_mut_errors: FxHashMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>,
/// Diagnostics to be reported buffer.
buffered: Vec<Diagnostic>,
/// Set to Some if we emit an error during borrowck
BorrowckErrors {
tcx,
buffered_move_errors: BTreeMap::new(),
+ buffered_mut_errors: Default::default(),
buffered: Default::default(),
tainted_by_errors: None,
}
}
}
+ pub fn get_buffered_mut_error(
+ &mut self,
+ span: Span,
+ ) -> Option<(DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)> {
+ self.errors.buffered_mut_errors.remove(&span)
+ }
+
+ pub fn buffer_mut_error(
+ &mut self,
+ span: Span,
+ t: DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ count: usize,
+ ) {
+ self.errors.buffered_mut_errors.insert(span, (t, count));
+ }
+
pub fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
// Buffer any move errors that we collected and de-duplicated.
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
// We have already set tainted for this error, so just buffer it.
diag.buffer(&mut self.errors.buffered);
}
+ for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
+ if count > 10 {
+ diag.note(&format!("...and {} other attempted mutable borrows", count - 10));
+ }
+ diag.buffer(&mut self.errors.buffered);
+ }
if !self.errors.buffered.is_empty() {
self.errors.buffered.sort_by_key(|diag| diag.sort_span);
self
}
- pub fn replace_span_with(&mut self, after: Span) -> &mut Self {
+ pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
let before = self.span.clone();
self.set_span(after);
for span_label in before.span_labels() {
if let Some(label) = span_label.label {
- if span_label.is_primary {
+ if span_label.is_primary && keep_label {
self.span.push_span_label(after, label);
} else {
self.span.push_span_label(span_label.span, label);
);
if !e.span.is_dummy() {
// early end of macro arm (#52866)
- e.replace_span_with(parser.token.span.shrink_to_hi());
+ e.replace_span_with(parser.token.span.shrink_to_hi(), true);
}
}
if e.span.is_dummy() {
// Get around lack of span in error (#30128)
- e.replace_span_with(site_span);
+ e.replace_span_with(site_span, true);
if !parser.sess.source_map().is_imported(arm_span) {
e.span_label(arm_span, "in this macro arm");
}
})) = call_node
{
if Some(rcvr.span) == err.span.primary_span() {
- err.replace_span_with(path.ident.span);
+ err.replace_span_with(path.ident.span, true);
}
}
if let Some(Node::Expr(hir::Expr {
// Outputs require mutable places
let v: Vec<u64> = vec![0, 1, 2];
+ //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
asm!("{}", in(reg) v[0]);
asm!("{}", out(reg) v[0]);
- //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
asm!("{}", inout(reg) v[0]);
- //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
// Sym operands must point to a function or static
| +++
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-5.rs:26:29
+ --> $DIR/type-check-5.rs:24:13
|
LL | let v: Vec<u64> = vec![0, 1, 2];
- | - help: consider changing this to be mutable: `mut v`
-LL | asm!("{}", in(reg) v[0]);
-LL | asm!("{}", out(reg) v[0]);
- | ^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-5.rs:28:31
- |
-LL | let v: Vec<u64> = vec![0, 1, 2];
- | - help: consider changing this to be mutable: `mut v`
+ | ^
+ | |
+ | not mutable
+ | help: consider changing this to be mutable: `mut v`
...
+LL | asm!("{}", out(reg) v[0]);
+ | - cannot borrow as mutable
LL | asm!("{}", inout(reg) v[0]);
- | ^ cannot borrow as mutable
+ | - cannot borrow as mutable
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0381, E0596.
For more information about an error, try `rustc --explain E0381`.
--- /dev/null
+fn main() {
+ let v = Vec::new(); //~ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+}
--- /dev/null
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+ --> $DIR/many-mutable-borrows.rs:2:9
+ |
+LL | let v = Vec::new();
+ | ^
+ | |
+ | not mutable
+ | help: consider changing this to be mutable: `mut v`
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+ |
+ = note: ...and 5 other attempted mutable borrows
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
#![crate_type = "rlib"]
pub fn f(b: &mut i32) {
- //~^ NOTE the binding is already a mutable borrow
+ //~^ ERROR cannot borrow
+ //~| NOTE not mutable
//~| NOTE the binding is already a mutable borrow
h(&mut b);
- //~^ ERROR cannot borrow
- //~| NOTE cannot borrow as mutable
+ //~^ NOTE cannot borrow as mutable
//~| HELP try removing `&mut` here
g(&mut &mut b);
- //~^ ERROR cannot borrow
- //~| NOTE cannot borrow as mutable
+ //~^ NOTE cannot borrow as mutable
//~| HELP try removing `&mut` here
}
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
- --> $DIR/mut-borrow-of-mut-ref.rs:7:7
+ --> $DIR/mut-borrow-of-mut-ref.rs:4:10
|
+LL | pub fn f(b: &mut i32) {
+ | ^ not mutable
+...
LL | h(&mut b);
- | ^^^^^^ cannot borrow as mutable
+ | ------ cannot borrow as mutable
+...
+LL | g(&mut &mut b);
+ | ------ cannot borrow as mutable
|
note: the binding is already a mutable borrow
--> $DIR/mut-borrow-of-mut-ref.rs:4:13
LL - h(&mut b);
LL + h(b);
|
-
-error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
- --> $DIR/mut-borrow-of-mut-ref.rs:11:12
- |
-LL | g(&mut &mut b);
- | ^^^^^^ cannot borrow as mutable
- |
-note: the binding is already a mutable borrow
- --> $DIR/mut-borrow-of-mut-ref.rs:4:13
- |
-LL | pub fn f(b: &mut i32) {
- | ^^^^^^^^
help: try removing `&mut` here
|
LL - g(&mut &mut b);
|
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
- --> $DIR/mut-borrow-of-mut-ref.rs:18:12
+ --> $DIR/mut-borrow-of-mut-ref.rs:17:12
|
LL | h(&mut &mut b);
| ^^^^^^ cannot borrow as mutable
|
note: the binding is already a mutable borrow
- --> $DIR/mut-borrow-of-mut-ref.rs:17:13
+ --> $DIR/mut-borrow-of-mut-ref.rs:16:13
|
LL | pub fn g(b: &mut i32) {
| ^^^^^^^^
|
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
- --> $DIR/mut-borrow-of-mut-ref.rs:35:5
+ --> $DIR/mut-borrow-of-mut-ref.rs:34:5
|
LL | f.bar();
| ^^^^^^^ cannot borrow as mutable
LL | pub fn baz(mut f: &mut String) {
| +++
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0596`.
});
}
-fn imm_local(x: (i32,)) {
- &mut x; //~ ERROR
- &mut x.0; //~ ERROR
+fn imm_local(x: (i32,)) { //~ ERROR
+ &mut x;
+ &mut x.0;
}
fn imm_capture(x: (i32,)) {
| ^^^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
- --> $DIR/mutability-errors.rs:54:5
+ --> $DIR/mutability-errors.rs:53:14
|
LL | fn imm_local(x: (i32,)) {
- | - help: consider changing this to be mutable: `mut x`
-LL | &mut x;
- | ^^^^^^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
- --> $DIR/mutability-errors.rs:55:5
- |
-LL | fn imm_local(x: (i32,)) {
- | - help: consider changing this to be mutable: `mut x`
+ | ^
+ | |
+ | not mutable
+ | help: consider changing this to be mutable: `mut x`
LL | &mut x;
+ | ------ cannot borrow as mutable
LL | &mut x.0;
- | ^^^^^^^^ cannot borrow as mutable
+ | -------- cannot borrow as mutable
error[E0594]: cannot assign to `x`, as it is not declared as mutable
--> $DIR/mutability-errors.rs:60:9
LL | &mut X.0;
| ^^^^^^^^ cannot borrow as mutable
-error: aborting due to 38 previous errors
+error: aborting due to 37 previous errors
Some errors have detailed explanations: E0594, E0596.
For more information about an error, try `rustc --explain E0594`.