diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b945d687043b4..9e5fb674772d5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -785,13 +785,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { issued_borrow: &BorrowData<'tcx>, explanation: BorrowExplanation, ) { - let used_in_call = - matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _)); + let used_in_call = matches!( + explanation, + BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _) + ); if !used_in_call { debug!("not later used in call"); return; } + let use_span = + if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation { + Some(use_span) + } else { + None + }; + let outer_call_loc = if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location { loc @@ -835,7 +844,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc); let inner_call_span = inner_call_term.source_info.span; - let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span; + let outer_call_span = match use_span { + Some(span) => span, + None => outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span, + }; if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) { // FIXME: This stops the suggestion in some cases where it should be emitted. // Fix the spans for those cases so it's emitted correctly. @@ -845,8 +857,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); return; } - err.span_help(inner_call_span, "try adding a local storing this argument..."); - err.span_help(outer_call_span, "...and then using that local as the argument to this call"); + err.span_help( + inner_call_span, + &format!( + "try adding a local storing this{}...", + if use_span.is_some() { "" } else { " argument" } + ), + ); + err.span_help( + outer_call_span, + &format!( + "...and then using that local {}", + if use_span.is_some() { "here" } else { "as the argument to this call" } + ), + ); } fn suggest_split_at_mut_if_applicable( @@ -1912,10 +1936,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { "cannot assign twice to immutable variable" }; - if span != assigned_span { - if !from_arg { - err.span_label(assigned_span, format!("first assignment to {}", place_description)); - } + if span != assigned_span && !from_arg { + err.span_label(assigned_span, format!("first assignment to {}", place_description)); } if let Some(decl) = local_decl && let Some(name) = local_name diff --git a/src/test/ui/borrowck/suggest-local-var-for-vector.rs b/src/test/ui/borrowck/suggest-local-var-for-vector.rs new file mode 100644 index 0000000000000..40f013f6a78a7 --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-for-vector.rs @@ -0,0 +1,4 @@ +fn main() { + let mut vec = vec![0u32; 420]; + vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable +} diff --git a/src/test/ui/borrowck/suggest-local-var-for-vector.stderr b/src/test/ui/borrowck/suggest-local-var-for-vector.stderr new file mode 100644 index 0000000000000..615fffcd578ad --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-for-vector.stderr @@ -0,0 +1,24 @@ +error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable + --> $DIR/suggest-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ----^^^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/suggest-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^ +help: ...and then using that local here + --> $DIR/suggest-local-var-for-vector.rs:3:5 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs new file mode 100644 index 0000000000000..40f013f6a78a7 --- /dev/null +++ b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs @@ -0,0 +1,4 @@ +fn main() { + let mut vec = vec![0u32; 420]; + vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable +} diff --git a/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr new file mode 100644 index 0000000000000..e3a16eddfd5ec --- /dev/null +++ b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr @@ -0,0 +1,24 @@ +error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable + --> $DIR/suggest-storing-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ----^^^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/suggest-storing-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^ +help: ...and then using that local here + --> $DIR/suggest-storing-local-var-for-vector.rs:3:5 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr index 50d277a12f74f..0f2daaf99d914 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr @@ -54,6 +54,17 @@ LL | i[i[3]] = 4; | | immutable borrow occurs here | mutable borrow occurs here | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/two-phase-nonrecv-autoref.rs:138:7 + | +LL | i[i[3]] = 4; + | ^^^^ +help: ...and then using that local here + --> $DIR/two-phase-nonrecv-autoref.rs:138:5 + | +LL | i[i[3]] = 4; + | ^^^^^^^ error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable --> $DIR/two-phase-nonrecv-autoref.rs:143:7 @@ -64,6 +75,17 @@ LL | i[i[3]] = i[4]; | | immutable borrow occurs here | mutable borrow occurs here | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/two-phase-nonrecv-autoref.rs:143:7 + | +LL | i[i[3]] = i[4]; + | ^^^^ +help: ...and then using that local here + --> $DIR/two-phase-nonrecv-autoref.rs:143:5 + | +LL | i[i[3]] = i[4]; + | ^^^^^^^ error: aborting due to 7 previous errors