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 7555bd60849..118ca985b87 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -287,3 +287,9 @@ mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count - *[other] these patterns } will always match, so the loop will never exit .help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it + +mir_build_borrow_of_moved_value = borrow of moved value + .label = value moved into `{$name}` here + .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 diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index eecef26b94c..639c07f4194 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -562,3 +562,19 @@ pub struct IrrefutableLetPatternsLetElse { pub struct IrrefutableLetPatternsWhileLet { pub count: usize, } + +#[derive(SessionDiagnostic)] +#[diag(mir_build::borrow_of_moved_value)] +pub struct BorrowOfMovedValue<'tcx> { + #[primary_span] + pub span: Span, + #[label] + #[label(mir_build::occurs_because_label)] + pub binding_span: Span, + #[label(mir_build::value_borrowed_label)] + pub conflicts_ref: Vec, + pub name: Ident, + pub ty: Ty<'tcx>, + #[suggestion(code = "ref ", applicability = "machine-applicable")] + pub suggest_borrowing: Option, +} 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 a488253b992..3b6b188bc6c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -962,24 +962,14 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa } }); if !conflicts_ref.is_empty() { - let occurs_because = format!( - "move occurs because `{}` has type `{}` which does not implement the `Copy` trait", + sess.emit_err(BorrowOfMovedValue { + span: pat.span, + binding_span, + conflicts_ref, name, - typeck_results.node_type(pat.hir_id), - ); - let mut err = sess.struct_span_err(pat.span, "borrow of moved value"); - err.span_label(binding_span, format!("value moved into `{}` here", name)) - .span_label(binding_span, occurs_because) - .span_labels(conflicts_ref, "value borrowed here after move"); - if pat.span.contains(binding_span) { - err.span_suggestion_verbose( - binding_span.shrink_to_lo(), - "borrow this binding in the pattern to avoid moving the value", - "ref ".to_string(), - Applicability::MachineApplicable, - ); - } - err.emit(); + ty: typeck_results.node_type(pat.hir_id), + suggest_borrowing: pat.span.contains(binding_span).then(|| binding_span.shrink_to_lo()), + }); } return; }