diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index b1def189230f7..12f2b31addda6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -1,3 +1,6 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] + use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 2f61849c383c5..40a1ebd3f77f8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -1,3 +1,6 @@ +// #![deny(rustc::untranslatable_diagnostic)] +// #![deny(rustc::diagnostic_outside_of_impl)] + //! Print diagnostics to explain why values are borrowed. use std::collections::VecDeque; @@ -16,6 +19,10 @@ use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, DesugaringKind, Span}; use crate::region_infer::BlameConstraint; +use crate::session_diagnostics::{ + BorrowLaterBorrowUsedLaterInLoop, BorrowUsedHere, BorrowUsedLater, BorrowUsedLaterInLoop, + MustValidFor, UsedLaterDropped, +}; use crate::{ borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt, WriteKind, @@ -67,20 +74,28 @@ impl<'tcx> BorrowExplanation<'tcx> { ) { match *self { BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => { - let message = match later_use_kind { - LaterUseKind::TraitCapture => "captured here by trait object", - LaterUseKind::ClosureCapture => "captured here by closure", - LaterUseKind::Call => "used by call", - LaterUseKind::FakeLetRead => "stored here", - LaterUseKind::Other => "used here", - }; // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { - err.span_label( - var_or_use_span, - format!("{}borrow later {}", borrow_desc, message), - ); + let sub_err = match later_use_kind { + LaterUseKind::TraitCapture => { + BorrowUsedLater::TraitCapture { borrow_desc, span: var_or_use_span } + } + LaterUseKind::ClosureCapture => BorrowUsedLater::ClosureCapture { + borrow_desc, + span: var_or_use_span, + }, + LaterUseKind::Call => { + BorrowUsedLater::Call { borrow_desc, span: var_or_use_span } + } + LaterUseKind::FakeLetRead => { + BorrowUsedLater::FakeLetRead { borrow_desc, span: var_or_use_span } + } + LaterUseKind::Other => { + BorrowUsedLater::Other { borrow_desc, span: var_or_use_span } + } + }; + err.subdiagnostic(sub_err); } } else { // path_span must be `Some` as otherwise the if condition is true @@ -88,44 +103,92 @@ impl<'tcx> BorrowExplanation<'tcx> { // path_span is only present in the case of closure capture assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture)); if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) { - let path_label = "used here by closure"; - let capture_kind_label = message; - err.span_label( - var_or_use_span, - format!("{}borrow later {}", borrow_desc, capture_kind_label), - ); - err.span_label(path_span, path_label); + let sub_err = match later_use_kind { + LaterUseKind::TraitCapture => { + BorrowUsedLater::TraitCapture { borrow_desc, span: var_or_use_span } + } + LaterUseKind::ClosureCapture => BorrowUsedLater::ClosureCapture { + borrow_desc, + span: var_or_use_span, + }, + LaterUseKind::Call => { + BorrowUsedLater::Call { borrow_desc, span: var_or_use_span } + } + LaterUseKind::FakeLetRead => { + BorrowUsedLater::FakeLetRead { borrow_desc, span: var_or_use_span } + } + LaterUseKind::Other => { + BorrowUsedLater::Other { borrow_desc, span: var_or_use_span } + } + }; + err.subdiagnostic(sub_err); + let sub_label = BorrowUsedHere::ByClosure { path_span }; + err.subdiagnostic(sub_label); } } } BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) => { - let message = match later_use_kind { - LaterUseKind::TraitCapture => { - "borrow captured here by trait object, in later iteration of loop" - } - LaterUseKind::ClosureCapture => { - "borrow captured here by closure, in later iteration of loop" - } - LaterUseKind::Call => "borrow used by call, in later iteration of loop", - LaterUseKind::FakeLetRead => "borrow later stored here", - LaterUseKind::Other => "borrow used here, in later iteration of loop", - }; // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { - err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message)); + let sub_err = match later_use_kind { + LaterUseKind::TraitCapture => BorrowUsedLaterInLoop::TraitCapture { + borrow_desc, + span: var_or_use_span, + }, + LaterUseKind::ClosureCapture => BorrowUsedLaterInLoop::ClosureCapture { + borrow_desc, + span: var_or_use_span, + }, + LaterUseKind::Call => { + BorrowUsedLaterInLoop::Call { borrow_desc, span: var_or_use_span } + } + LaterUseKind::FakeLetRead => BorrowUsedLaterInLoop::FakeLetRead { + borrow_desc, + span: var_or_use_span, + }, + LaterUseKind::Other => { + BorrowUsedLaterInLoop::Other { borrow_desc, span: var_or_use_span } + } + }; + err.subdiagnostic(sub_err); + // err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message)); } else { // path_span must be `Some` as otherwise the if condition is true let path_span = path_span.unwrap(); // path_span is only present in the case of closure capture assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture)); if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { - let path_label = "used here by closure"; - let capture_kind_label = message; - err.span_label( - var_or_use_span, - format!("{}borrow later {}", borrow_desc, capture_kind_label), - ); - err.span_label(path_span, path_label); + let sub_err = match later_use_kind { + LaterUseKind::TraitCapture => { + BorrowLaterBorrowUsedLaterInLoop::TraitCapture { + borrow_desc, + span: var_or_use_span, + } + } + LaterUseKind::ClosureCapture => { + BorrowLaterBorrowUsedLaterInLoop::ClosureCapture { + borrow_desc, + span: var_or_use_span, + } + } + LaterUseKind::Call => BorrowLaterBorrowUsedLaterInLoop::Call { + borrow_desc, + span: var_or_use_span, + }, + LaterUseKind::FakeLetRead => { + BorrowLaterBorrowUsedLaterInLoop::FakeLetRead { + borrow_desc, + span: var_or_use_span, + } + } + LaterUseKind::Other => BorrowLaterBorrowUsedLaterInLoop::Other { + borrow_desc, + span: var_or_use_span, + }, + }; + err.subdiagnostic(sub_err); + let sub_label = BorrowUsedHere::ByClosure { path_span }; + err.subdiagnostic(sub_label); } } } @@ -161,41 +224,33 @@ impl<'tcx> BorrowExplanation<'tcx> { match local_names[dropped_local] { Some(local_name) if !local_decl.from_compiler_desugaring() => { - let message = format!( - "{B}borrow might be used here, when `{LOC}` is dropped \ - and runs the {DTOR} for {TYPE}", - B = borrow_desc, - LOC = local_name, - TYPE = type_desc, - DTOR = dtor_desc - ); - err.span_label(body.source_info(drop_loc).span, message); + let sub_label = UsedLaterDropped::UsedHere { + borrow_desc, + local_name: &local_name.to_ident_string(), + type_desc: &type_desc, + dtor_desc, + span: body.source_info(drop_loc).span, + }; + err.subdiagnostic(sub_label); if should_note_order { - err.note( - "values in a scope are dropped \ - in the opposite order they are defined", - ); + let sub_note = UsedLaterDropped::OppositeOrder {}; + err.subdiagnostic(sub_note); } } _ => { - err.span_label( - local_decl.source_info.span, - format!( - "a temporary with access to the {B}borrow \ - is created here ...", - B = borrow_desc - ), - ); - let message = format!( - "... and the {B}borrow might be used here, \ - when that temporary is dropped \ - and runs the {DTOR} for {TYPE}", - B = borrow_desc, - TYPE = type_desc, - DTOR = dtor_desc - ); - err.span_label(body.source_info(drop_loc).span, message); + let sub_label = UsedLaterDropped::TemporaryCreatedHere { + borrow_desc, + span: local_decl.source_info.span, + }; + err.subdiagnostic(sub_label); + let sub_label_2 = UsedLaterDropped::MightUsedHere { + borrow_desc, + type_desc: &type_desc, + dtor_desc, + span: body.source_info(drop_loc).span, + }; + err.subdiagnostic(sub_label_2); if let Some(info) = &local_decl.is_block_tail { if info.tail_result_is_ignored { @@ -207,21 +262,16 @@ impl<'tcx> BorrowExplanation<'tcx> { }) .unwrap_or(false) { - err.span_suggestion_verbose( - info.span.shrink_to_hi(), - "consider adding semicolon after the expression so its \ - temporaries are dropped sooner, before the local variables \ - declared by the block are dropped", - ";", - Applicability::MaybeIncorrect, - ); + let sub_suggest = UsedLaterDropped::AddSemicolon { + span: info.span.shrink_to_hi(), + }; + err.subdiagnostic(sub_suggest); } } else { - err.note( - "the temporary is part of an expression at the end of a \ - block;\nconsider forcing this temporary to be dropped sooner, \ - before the block's local variables are dropped", - ); + let sub_note = UsedLaterDropped::ManualDrop {}; + err.subdiagnostic(sub_note); + + //FIXME: waiting for multipart suggestion derive err.multipart_suggestion( "for example, you could save the expression's value in a new \ local variable `x` and then make `x` be the expression at the \ @@ -247,25 +297,22 @@ impl<'tcx> BorrowExplanation<'tcx> { region_name.highlight_region_name(err); if let Some(desc) = opt_place_desc { - err.span_label( + let sub_label = MustValidFor::Borrowed { + category: category.description(), + desc, + region_name, span, - format!( - "{}requires that `{}` is borrowed for `{}`", - category.description(), - desc, - region_name, - ), - ); + }; + err.subdiagnostic(sub_label); } else { - err.span_label( + //FIXME: src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs + let sub_label = MustValidFor::Lasts { + category: category.description(), + borrow_desc, + region_name, span, - format!( - "{}requires that {}borrow lasts for `{}`", - category.description(), - borrow_desc, - region_name, - ), - ); + }; + err.subdiagnostic(sub_label); }; self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name); diff --git a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs index b3edc35dc3642..498e9834354b7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs @@ -1,3 +1,6 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] + use std::collections::BTreeSet; use rustc_middle::mir::visit::{PlaceContext, Visitor}; diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs index b5a3081e56a7a..15f42e26cbf4a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs @@ -1,3 +1,6 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] + use std::collections::VecDeque; use std::rc::Rc; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index dd9590016b990..a9f6a4df9209f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1,3 +1,6 @@ +// #![deny(rustc::untranslatable_diagnostic)] +// #![deny(rustc::diagnostic_outside_of_impl)] + use rustc_errors::{ Applicability, Diagnostic, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, }; @@ -19,6 +22,7 @@ use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, BytePos, Span}; use crate::diagnostics::BorrowedContentSource; +use crate::session_diagnostics::ShowMutatingUpvar; use crate::MirBorrowckCtxt; use rustc_const_eval::util::collect_writes::FindAssignments; @@ -864,14 +868,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } else { bug!("not an upvar") }; - err.span_label( - *span, - format!( - "calling `{}` requires mutable binding due to {}", - self.describe_place(the_place_err).unwrap(), - reason - ), - ); + let place = self.describe_place(the_place_err).unwrap(); + let sub_label = ShowMutatingUpvar::RequireMutableBinding { place, reason, span: *span }; + err.subdiagnostic(sub_label); } } diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 5d750c6ca8c7b..ec4b1cffa96fc 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -157,3 +157,181 @@ pub(crate) enum RequireStaticErr { multi_span: MultiSpan, }, } + +//explain_borrow.rs + +#[derive(SessionSubdiagnostic)] +pub(crate) enum BorrowUsedHere { + #[label(borrowck::used_here_by_closure)] + ByClosure { + #[primary_span] + path_span: Span, + }, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum BorrowUsedLater<'a> { + #[label(borrowck::borrow_later_captured_by_trait_object)] + TraitCapture { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::borrow_later_captured_by_closure)] + ClosureCapture { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::borrow_later_used_by_call)] + Call { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::borrow_later_stored_here)] + FakeLetRead { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::borrow_later_used_here)] + Other { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum BorrowUsedLaterInLoop<'a> { + #[label(borrowck::trait_capture_borrow_in_later_iteration_loop)] + TraitCapture { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::closure_capture_borrow_in_later_iteration_loop)] + ClosureCapture { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::call_used_borrow_in_later_iteration_loop)] + Call { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::borrow_later_stored_here)] + FakeLetRead { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::used_borrow_in_later_iteration_loop)] + Other { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, +} +#[derive(SessionSubdiagnostic)] +pub(crate) enum BorrowLaterBorrowUsedLaterInLoop<'a> { + #[label(borrowck::bl_trait_capture_borrow_in_later_iteration_loop)] + TraitCapture { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::bl_closure_capture_borrow_in_later_iteration_loop)] + ClosureCapture { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::call_used_borrow_in_later_iteration_loop)] + Call { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::bl_borrow_later_stored_here)] + FakeLetRead { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::bl_used_borrow_in_later_iteration_loop)] + Other { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum UsedLaterDropped<'a> { + #[label(borrowck::drop_local_might_cause_borrow)] + UsedHere { + borrow_desc: &'a str, + local_name: &'a str, + type_desc: &'a str, + dtor_desc: &'a str, + #[primary_span] + span: Span, + }, + #[note(borrowck::var_dropped_in_wrong_order)] + OppositeOrder {}, + #[label(borrowck::temporary_access_to_borrow)] + TemporaryCreatedHere { + borrow_desc: &'a str, + #[primary_span] + span: Span, + }, + #[label(borrowck::drop_temporary_might_cause_borrow_use)] + MightUsedHere { + borrow_desc: &'a str, + type_desc: &'a str, + dtor_desc: &'a str, + #[primary_span] + span: Span, + }, + #[suggestion_verbose( + borrowck::consider_add_semicolon, + applicability = "maybe-incorrect", + code = ";" + )] + AddSemicolon { + #[primary_span] + span: Span, + }, + + #[note(borrowck::consider_forcing_temporary_drop_sooner)] + ManualDrop {}, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum MustValidFor<'a> { + #[label(borrowck::outlive_constraint_need_borrow_for)] + Borrowed { + category: &'a str, + desc: &'a str, + region_name: &'a RegionName, + #[primary_span] + span: Span, + }, +} + +//mutability_errors.rs + +#[derive(SessionSubdiagnostic)] +pub(crate) enum ShowMutatingUpvar { + #[label(borrowck::require_mutable_binding)] + RequireMutableBinding { + place: String, + reason: String, + #[primary_span] + span: Span, + }, +} diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl index 67f2156f32e50..2ac71d29cc25f 100644 --- a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl @@ -58,3 +58,78 @@ borrowck_returned_lifetime_short = borrowck_used_impl_require_static = the used `impl` has a `'static` requirement + +borrowck_borrow_later_captured_by_trait_object = + {$borrow_desc}borrow later captured here by trait object + +borrowck_borrow_later_captured_by_closure = + {$borrow_desc}borrow later captured here by closure + +borrowck_borrow_later_used_by_call = + {$borrow_desc}borrow later used by call + +borrowck_borrow_later_stored_here = + {$borrow_desc}borrow later stored here + +borrowck_borrow_later_used_here = + {$borrow_desc}borrow later used here + +borrowck_used_here_by_closure = + used here by closure + +borrowck_trait_capture_borrow_in_later_iteration_loop = + {$borrow_desc}borrow captured here by trait object, in later iteration of loop + +borrowck_closure_capture_borrow_in_later_iteration_loop = + {$borrow_desc}borrow captured here by closure, in later iteration of loop + +borrowck_call_used_borrow_in_later_iteration_loop = + {$borrow_desc}borrow used by call, in later iteration of loop + +borrowck_used_borrow_in_later_iteration_loop = + {$borrow_desc}borrow used here, in later iteration of loop + +borrowck_bl_trait_capture_borrow_in_later_iteration_loop = + {$borrow_desc}borrow later borrow captured here by trait object, in later iteration of loop + +borrowck_bl_closure_capture_borrow_in_later_iteration_loop = + {$borrow_desc}borrow later borrow captured here by closure, in later iteration of loop + +borrowck_bl_call_used_borrow_in_later_iteration_loop = + {$borrow_desc}borrow later borrow used by call, in later iteration of loop + +borrowck_bl_borrow_later_stored_here = + {$borrow_desc}borrow later borrow later stored here + +borrowck_bl_used_borrow_in_later_iteration_loop = + {$borrow_desc}borrow later borrow used here, in later iteration of loop + +borrowck_drop_local_might_cause_borrow = + {$borrow_desc}borrow might be used here, when `{$local_name}` is dropped and runs the {$dtor_desc} for {$type_desc} + +borrowck_var_dropped_in_wrong_order = + values in a scope are dropped in the opposite order they are defined + +borrowck_temporary_access_to_borrow = + a temporary with access to the {$borrow_desc}borrow is created here ... + +borrowck_drop_temporary_might_cause_borrow_use = ... and the {$borrow_desc}borrow might be used here, when that temporary is dropped and runs the {$dtor_desc} for {$type_desc} + +borrowck_consider_add_semicolon = + consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped + +borrowck_consider_forcing_temporary_drop_sooner = + the temporary is part of an expression at the end of a block; + consider forcing this temporary to be dropped sooner, before the block's local variables are dropped + +borrowck_perhaps_save_in_new_local_to_drop = + for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block + +borrowck_outlive_constraint_need_borrow_for = + {$category}requires that `{$desc}` is borrowed for `{$region_name}` + +borrowck_outlive_constraint_need_borrow_lasts_for = + {$category}requires that `{$borrow_desc}` lasts for `{$region_name}` + +borrowck_require_mutable_binding = + calling `{$place}` requires mutable binding due to {$reason}