| use rustc_errors::{codes::*, struct_span_code_err, DiagCtxt, DiagnosticBuilder}; |
| use rustc_middle::ty::{self, Ty, TyCtxt}; |
| use rustc_span::Span; |
| |
| impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { |
| pub fn dcx(&self) -> &'tcx DiagCtxt { |
| self.infcx.dcx() |
| } |
| |
| pub(crate) fn cannot_move_when_borrowed( |
| &self, |
| span: Span, |
| borrow_span: Span, |
| place: &str, |
| borrow_place: &str, |
| value_place: &str, |
| ) -> DiagnosticBuilder<'tcx> { |
| self.dcx().create_err(crate::session_diagnostics::MoveBorrow { |
| place, |
| span, |
| borrow_place, |
| value_place, |
| borrow_span, |
| }) |
| } |
| |
| pub(crate) fn cannot_use_when_mutably_borrowed( |
| &self, |
| span: Span, |
| desc: &str, |
| borrow_span: Span, |
| borrow_desc: &str, |
| ) -> DiagnosticBuilder<'tcx> { |
| struct_span_code_err!( |
| self.dcx(), |
| span, |
| E0503, |
| "cannot use {} because it was mutably borrowed", |
| desc, |
| ) |
| .with_span_label(borrow_span, format!("{borrow_desc} is borrowed here")) |
| .with_span_label(span, format!("use of borrowed {borrow_desc}")) |
| } |
| |
| pub(crate) fn cannot_mutably_borrow_multiply( |
| &self, |
| new_loan_span: Span, |
| desc: &str, |
| opt_via: &str, |
| old_loan_span: Span, |
| old_opt_via: &str, |
| old_load_end_span: Option<Span>, |
| ) -> DiagnosticBuilder<'tcx> { |
| let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; |
| let mut err = struct_span_code_err!( |
| self.dcx(), |
| new_loan_span, |
| E0499, |
| "cannot borrow {}{} as mutable more than once at a time", |
| desc, |
| via(opt_via), |
| ); |
| if old_loan_span == new_loan_span { |
| // Both borrows are happening in the same place |
| // Meaning the borrow is occurring in a loop |
| err.span_label( |
| new_loan_span, |
| format!( |
| "{}{} was mutably borrowed here in the previous iteration of the loop{}", |
| desc, |
| via(opt_via), |
| opt_via, |
| ), |
| ); |
| if let Some(old_load_end_span) = old_load_end_span { |
| err.span_label(old_load_end_span, "mutable borrow ends here"); |
| } |
| } else { |
| err.span_label( |
| old_loan_span, |
| format!("first mutable borrow occurs here{}", via(old_opt_via)), |
| ); |
| err.span_label( |
| new_loan_span, |
| format!("second mutable borrow occurs here{}", via(opt_via)), |
| ); |
| if let Some(old_load_end_span) = old_load_end_span { |
| err.span_label(old_load_end_span, "first borrow ends here"); |
| } |
| } |
| err |
| } |
| |
| pub(crate) fn cannot_uniquely_borrow_by_two_closures( |
| &self, |
| new_loan_span: Span, |
| desc: &str, |
| old_loan_span: Span, |
| old_load_end_span: Option<Span>, |
| ) -> DiagnosticBuilder<'tcx> { |
| let mut err = struct_span_code_err!( |
| self.dcx(), |
| new_loan_span, |
| E0524, |
| "two closures require unique access to {} at the same time", |
| desc, |
| ); |
| if old_loan_span == new_loan_span { |
| err.span_label( |
| old_loan_span, |
| "closures are constructed here in different iterations of loop", |
| ); |
| } else { |
| err.span_label(old_loan_span, "first closure is constructed here"); |
| err.span_label(new_loan_span, "second closure is constructed here"); |
| } |
| if let Some(old_load_end_span) = old_load_end_span { |
| err.span_label(old_load_end_span, "borrow from first closure ends here"); |
| } |
| err |
| } |
| |
| pub(crate) fn cannot_uniquely_borrow_by_one_closure( |
| &self, |
| new_loan_span: Span, |
| container_name: &str, |
| desc_new: &str, |
| opt_via: &str, |
| old_loan_span: Span, |
| noun_old: &str, |
| old_opt_via: &str, |
| previous_end_span: Option<Span>, |
| ) -> DiagnosticBuilder<'cx> { |
| let mut err = struct_span_code_err!( |
| self.dcx(), |
| new_loan_span, |
| E0500, |
| "closure requires unique access to {} but {} is already borrowed{}", |
| desc_new, |
| noun_old, |
| old_opt_via, |
| ); |
| err.span_label( |
| new_loan_span, |
| format!("{container_name} construction occurs here{opt_via}"), |
| ); |
| err.span_label(old_loan_span, format!("borrow occurs here{old_opt_via}")); |
| if let Some(previous_end_span) = previous_end_span { |
| err.span_label(previous_end_span, "borrow ends here"); |
| } |
| err |
| } |
| |
| pub(crate) fn cannot_reborrow_already_uniquely_borrowed( |
| &self, |
| new_loan_span: Span, |
| container_name: &str, |
| desc_new: &str, |
| opt_via: &str, |
| kind_new: &str, |
| old_loan_span: Span, |
| old_opt_via: &str, |
| previous_end_span: Option<Span>, |
| second_borrow_desc: &str, |
| ) -> DiagnosticBuilder<'cx> { |
| let mut err = struct_span_code_err!( |
| self.dcx(), |
| new_loan_span, |
| E0501, |
| "cannot borrow {}{} as {} because previous closure requires unique access", |
| desc_new, |
| opt_via, |
| kind_new, |
| ); |
| err.span_label(new_loan_span, format!("{second_borrow_desc}borrow occurs here{opt_via}")); |
| err.span_label( |
| old_loan_span, |
| format!("{container_name} construction occurs here{old_opt_via}"), |
| ); |
| if let Some(previous_end_span) = previous_end_span { |
| err.span_label(previous_end_span, "borrow from closure ends here"); |
| } |
| err |
| } |
| |
| pub(crate) fn cannot_reborrow_already_borrowed( |
| &self, |
| span: Span, |
| desc_new: &str, |
| msg_new: &str, |
| kind_new: &str, |
| old_span: Span, |
| noun_old: &str, |
| kind_old: &str, |
| msg_old: &str, |
| old_load_end_span: Option<Span>, |
| ) -> DiagnosticBuilder<'cx> { |
| let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; |
| let mut err = struct_span_code_err!( |
| self.dcx(), |
| span, |
| E0502, |
| "cannot borrow {}{} as {} because {} is also borrowed as {}{}", |
| desc_new, |
| via(msg_new), |
| kind_new, |
| noun_old, |
| kind_old, |
| via(msg_old), |
| ); |
| |
| if msg_new == "" { |
| // If `msg_new` is empty, then this isn't a borrow of a union field. |
| err.span_label(span, format!("{kind_new} borrow occurs here")); |
| err.span_label(old_span, format!("{kind_old} borrow occurs here")); |
| } else { |
| // If `msg_new` isn't empty, then this a borrow of a union field. |
| err.span_label( |
| span, |
| format!( |
| "{kind_new} borrow of {msg_new} -- which overlaps with {msg_old} -- occurs here", |
| ), |
| ); |
| err.span_label(old_span, format!("{} borrow occurs here{}", kind_old, via(msg_old))); |
| } |
| |
| if let Some(old_load_end_span) = old_load_end_span { |
| err.span_label(old_load_end_span, format!("{kind_old} borrow ends here")); |
| } |
| err |
| } |
| |
| pub(crate) fn cannot_assign_to_borrowed( |
| &self, |
| span: Span, |
| borrow_span: Span, |
| desc: &str, |
| ) -> DiagnosticBuilder<'cx> { |
| struct_span_code_err!( |
| self.dcx(), |
| span, |
| E0506, |
| "cannot assign to {} because it is borrowed", |
| desc, |
| ) |
| .with_span_label(borrow_span, format!("{desc} is borrowed here")) |
| .with_span_label(span, format!("{desc} is assigned to here but it was already borrowed")) |
| } |
| |
| pub(crate) fn cannot_reassign_immutable( |
| &self, |
| span: Span, |
| desc: &str, |
| is_arg: bool, |
| ) -> DiagnosticBuilder<'cx> { |
| let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; |
| struct_span_code_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc) |
| } |
| |
| pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'tcx> { |
| struct_span_code_err!(self.dcx(), span, E0594, "cannot assign to {}", desc) |
| } |
| |
| pub(crate) fn cannot_move_out_of( |
| &self, |
| move_from_span: Span, |
| move_from_desc: &str, |
| ) -> DiagnosticBuilder<'cx> { |
| struct_span_code_err!( |
| self.dcx(), |
| move_from_span, |
| E0507, |
| "cannot move out of {}", |
| move_from_desc |
| ) |
| } |
| |
| /// Signal an error due to an attempt to move out of the interior |
| /// of an array or slice. `is_index` is None when error origin |
| /// didn't capture whether there was an indexing operation or not. |
| pub(crate) fn cannot_move_out_of_interior_noncopy( |
| &self, |
| move_from_span: Span, |
| ty: Ty<'_>, |
| is_index: Option<bool>, |
| ) -> DiagnosticBuilder<'cx> { |
| let type_name = match (&ty.kind(), is_index) { |
| (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", |
| (&ty::Slice(_), _) => "slice", |
| _ => span_bug!(move_from_span, "this path should not cause illegal move"), |
| }; |
| struct_span_code_err!( |
| self.dcx(), |
| move_from_span, |
| E0508, |
| "cannot move out of type `{}`, a non-copy {}", |
| ty, |
| type_name, |
| ) |
| .with_span_label(move_from_span, "cannot move out of here") |
| } |
| |
| pub(crate) fn cannot_move_out_of_interior_of_drop( |
| &self, |
| move_from_span: Span, |
| container_ty: Ty<'_>, |
| ) -> DiagnosticBuilder<'cx> { |
| struct_span_code_err!( |
| self.dcx(), |
| move_from_span, |
| E0509, |
| "cannot move out of type `{}`, which implements the `Drop` trait", |
| container_ty, |
| ) |
| .with_span_label(move_from_span, "cannot move out of here") |
| } |
| |
| pub(crate) fn cannot_act_on_moved_value( |
| &self, |
| use_span: Span, |
| verb: &str, |
| optional_adverb_for_moved: &str, |
| moved_path: Option<String>, |
| ) -> DiagnosticBuilder<'tcx> { |
| let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default(); |
| |
| struct_span_code_err!( |
| self.dcx(), |
| use_span, |
| E0382, |
| "{} of {}moved value{}", |
| verb, |
| optional_adverb_for_moved, |
| moved_path, |
| ) |
| } |
| |
| pub(crate) fn cannot_borrow_path_as_mutable_because( |
| &self, |
| span: Span, |
| path: &str, |
| reason: &str, |
| ) -> DiagnosticBuilder<'tcx> { |
| struct_span_code_err!( |
| self.dcx(), |
| span, |
| E0596, |
| "cannot borrow {} as mutable{}", |
| path, |
| reason |
| ) |
| } |
| |
| pub(crate) fn cannot_mutate_in_immutable_section( |
| &self, |
| mutate_span: Span, |
| immutable_span: Span, |
| immutable_place: &str, |
| immutable_section: &str, |
| action: &str, |
| ) -> DiagnosticBuilder<'tcx> { |
| struct_span_code_err!( |
| self.dcx(), |
| mutate_span, |
| E0510, |
| "cannot {} {} in {}", |
| action, |
| immutable_place, |
| immutable_section, |
| ) |
| .with_span_label(mutate_span, format!("cannot {action}")) |
| .with_span_label(immutable_span, format!("value is immutable in {immutable_section}")) |
| } |
| |
| pub(crate) fn cannot_borrow_across_coroutine_yield( |
| &self, |
| span: Span, |
| yield_span: Span, |
| ) -> DiagnosticBuilder<'tcx> { |
| let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind; |
| struct_span_code_err!( |
| self.dcx(), |
| span, |
| E0626, |
| "borrow may still be in use when {coroutine_kind:#} yields", |
| ) |
| .with_span_label(yield_span, "possible yield occurs here") |
| } |
| |
| pub(crate) fn cannot_borrow_across_destructor( |
| &self, |
| borrow_span: Span, |
| ) -> DiagnosticBuilder<'tcx> { |
| struct_span_code_err!( |
| self.dcx(), |
| borrow_span, |
| E0713, |
| "borrow may still be in use when destructor runs", |
| ) |
| } |
| |
| pub(crate) fn path_does_not_live_long_enough( |
| &self, |
| span: Span, |
| path: &str, |
| ) -> DiagnosticBuilder<'tcx> { |
| struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,) |
| } |
| |
| pub(crate) fn cannot_return_reference_to_local( |
| &self, |
| span: Span, |
| return_kind: &str, |
| reference_desc: &str, |
| path_desc: &str, |
| ) -> DiagnosticBuilder<'tcx> { |
| struct_span_code_err!( |
| self.dcx(), |
| span, |
| E0515, |
| "cannot {RETURN} {REFERENCE} {LOCAL}", |
| RETURN = return_kind, |
| REFERENCE = reference_desc, |
| LOCAL = path_desc, |
| ) |
| .with_span_label( |
| span, |
| format!("{return_kind}s a {reference_desc} data owned by the current function"), |
| ) |
| } |
| |
| pub(crate) fn cannot_capture_in_long_lived_closure( |
| &self, |
| closure_span: Span, |
| closure_kind: &str, |
| borrowed_path: &str, |
| capture_span: Span, |
| scope: &str, |
| ) -> DiagnosticBuilder<'tcx> { |
| struct_span_code_err!( |
| self.dcx(), |
| closure_span, |
| E0373, |
| "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \ |
| which is owned by the current {scope}", |
| ) |
| .with_span_label(capture_span, format!("{borrowed_path} is borrowed here")) |
| .with_span_label(closure_span, format!("may outlive borrowed value {borrowed_path}")) |
| } |
| |
| pub(crate) fn thread_local_value_does_not_live_long_enough( |
| &self, |
| span: Span, |
| ) -> DiagnosticBuilder<'tcx> { |
| struct_span_code_err!( |
| self.dcx(), |
| span, |
| E0712, |
| "thread-local variable borrowed past end of function", |
| ) |
| } |
| |
| pub(crate) fn temporary_value_borrowed_for_too_long( |
| &self, |
| span: Span, |
| ) -> DiagnosticBuilder<'tcx> { |
| struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",) |
| } |
| } |
| |
| pub(crate) fn borrowed_data_escapes_closure<'tcx>( |
| tcx: TyCtxt<'tcx>, |
| escape_span: Span, |
| escapes_from: &str, |
| ) -> DiagnosticBuilder<'tcx> { |
| struct_span_code_err!( |
| tcx.dcx(), |
| escape_span, |
| E0521, |
| "borrowed data escapes outside of {}", |
| escapes_from, |
| ) |
| } |