diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 118ca985b87ff..94e061a2af6a8 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -293,3 +293,9 @@ mir_build_borrow_of_moved_value = borrow of moved value .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait .value_borrowed_label = value borrowed here after move .suggest_borrowing = borrow this binding in the pattern to avoid moving the value + +mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time + .label = first mutable borrow, by `{$name}`, occurs here + .mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here + .immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here + .moved = also moved into `{$name_moved}` here diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 639c07f419401..dd715fcfc6c58 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -578,3 +578,37 @@ pub struct BorrowOfMovedValue<'tcx> { #[suggestion(code = "ref ", applicability = "machine-applicable")] pub suggest_borrowing: Option, } + +#[derive(SessionDiagnostic)] +#[diag(mir_build::multiple_mut_borrows)] +pub struct MultipleMutBorrows { + #[primary_span] + pub span: Span, + #[label] + pub binding_span: Span, + #[subdiagnostic] + pub occurences: Vec, + pub name: Ident, +} + +#[derive(SessionSubdiagnostic)] +pub enum MultipleMutBorrowOccurence { + #[label(mir_build::mutable_borrow)] + Mutable { + #[primary_span] + span: Span, + name_mut: Ident, + }, + #[label(mir_build::immutable_borrow)] + Immutable { + #[primary_span] + span: Span, + name_immut: Ident, + }, + #[label(mir_build::moved)] + Moved { + #[primary_span] + span: Span, + name_moved: Ident, + }, +} diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 3b6b188bc6cfb..374942ee798b8 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -999,19 +999,19 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa // Report errors if any. if !conflicts_mut_mut.is_empty() { // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. - let mut err = sess - .struct_span_err(pat.span, "cannot borrow value as mutable more than once at a time"); - err.span_label(binding_span, format!("first mutable borrow, by `{}`, occurs here", name)); + let mut occurences = vec![]; + for (span, name) in conflicts_mut_mut { - err.span_label(span, format!("another mutable borrow, by `{}`, occurs here", name)); + occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut: name }); } for (span, name) in conflicts_mut_ref { - err.span_label(span, format!("also borrowed as immutable, by `{}`, here", name)); + occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut: name }); } for (span, name) in conflicts_move { - err.span_label(span, format!("also moved into `{}` here", name)); + occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved: name }); } - err.emit(); + + sess.emit_err(MultipleMutBorrows { span: pat.span, binding_span, occurences, name }); } else if !conflicts_mut_ref.is_empty() { // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. let (primary, also) = match mut_outer {