diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index bf14d5eb9a0a8..5e928a73d1729 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -1,3 +1,17 @@ +borrowck_and_data_moved_here = ...and here + +borrowck_assign_data_behind_const_pointer = + cannot assign to data in a `*const` pointer + +borrowck_assign_data_behind_deref = + cannot assign to data in {$name} + +borrowck_assign_data_behind_index = + cannot assign to data in an index of {$name} + +borrowck_assign_data_behind_ref = + cannot assign to data in a `&` reference + borrowck_assign_due_to_use_closure = assignment occurs due to use in closure @@ -10,15 +24,93 @@ borrowck_assign_part_due_to_use_closure = borrowck_assign_part_due_to_use_coroutine = assign to part occurs due to use in coroutine +borrowck_assign_place_behind_const_pointer = + cannot assign to `{$place}`, which is behind a `*const` pointer + +borrowck_assign_place_behind_deref = + cannot assign to `{$place}`, which is behind {$name} + +borrowck_assign_place_behind_index = + cannot assign to `{$place}`, which is behind an index of {$ty} + +borrowck_assign_place_behind_ref = + cannot assign to `{$place}`, which is behind a `&` reference + +borrowck_assign_place_declared_immute = + cannot assign to `{$place}`, as it is not declared as mutable + +borrowck_assign_place_in_fn = + cannot assign to `{$place}`, as it is a captured variable in a `Fn` closure + +borrowck_assign_place_in_pattern_guard_immute = + cannot assign to `{$place}`, as it is immutable for the pattern guard + +borrowck_assign_place_static = + cannot assign to immutable static item `{$place}` + +borrowck_assign_symbol_declared_immute = + cannot assign to `{$place}`, as `{$name}` is not declared as mutable + +borrowck_assign_symbol_static = + cannot assign to `{$place}`, as `{$static_name}` is an immutable static item + +borrowck_assign_upvar_in_fn = + cannot assign to `{$place}`, as `Fn` closures cannot mutate their captured variables + borrowck_borrow_due_to_use_closure = borrow occurs due to use in closure borrowck_borrow_due_to_use_coroutine = borrow occurs due to use in coroutine +borrowck_borrow_occurs_here = {$kind} borrow occurs here + +borrowck_borrow_occurs_here_overlap = + {$kind_new} borrow of {$msg_new} -- which overlaps with {$msg_old} -- occurs here + +borrowck_borrow_occurs_here_via = + {$kind_old} borrow occurs {$is_msg_old_empty -> + *[true] here + [false] here (via {$msg_old}) + } + +borrowck_borrowed_temporary_value_dropped = + temporary value dropped while borrowed + borrowck_calling_operator_moves_lhs = calling this operator moves the left-hand side +borrowck_cannot_assign = + cannot assign + +borrowck_cannot_assign_to_borrowed = + cannot assign to {$desc -> + [value] value + *[other] {$desc} + } because it is borrowed + .label = {$desc -> + [value] value + *[other] {$desc} + } is assigned to here but it was already borrowed + .borrow_here_label = {$desc -> + [value] value + *[other] {$desc} + } is borrowed here + +borrowck_cannot_borrow_across_coroutine_yield = + borrow may still be in use when {$coroutine_kind} yields + .label = possible yield occurs here + +borrowck_cannot_borrow_across_destructor = + borrow may still be in use when destructor runs + +borrowck_cannot_borrow_mut = + cannot borrow as mutable + +borrowck_cannot_move_out_of_interior_of_drop = + cannot move out of type `{$container_ty}`, which implements the `Drop` trait + .label = cannot move out of here + borrowck_cannot_move_when_borrowed = cannot move out of {$place -> [value] value @@ -33,6 +125,85 @@ borrowck_cannot_move_when_borrowed = *[other] {$value_place} } occurs here +borrowck_cannot_mutably_borrow_multiply = + cannot borrow {$is_place_empty -> + *[true] {$new_place_name} + [false] {$new_place_name} (via {$place}) + } as mutable more than once at a time + .label = first mutable borrow occurs {$is_old_place_empty -> + *[true] here + [false] here (via {$old_place}) + } + .second_mut_borrow_label = second mutable borrow occurs {$is_place_empty -> + *[true] here + [false] here (via {$place}) + } + .first_mut_end_label = first borrow ends here + +borrowck_cannot_mutably_borrow_multiply_same_span = + cannot borrow {$is_place_empty -> + *[true] {$new_place_name} + [false] {$new_place_name} (via {$place}) + } as mutable more than once at a time + .label = mutable borrow ends here + +borrowck_cannot_reassign_immutable_arg = + cannot assign to immutable argument {$place} + +borrowck_cannot_reassign_immutable_var = + cannot assign twice to immutable variable {$place} + +borrowck_cannot_reborrow_already_borrowed = + cannot borrow {$is_msg_new_empty -> + *[true] {$desc_new} + [false] {$desc_new} (via {$msg_new}) + } as {$kind_new} because {$noun_old} is also borrowed as {$is_msg_old_empty -> + *[true] {$kind_old} + [false] {$kind_old} (via {$msg_old}) + } + .label = {$kind_old} borrow ends here + +borrowck_cannot_reborrow_already_uniquely_borrowed = + cannot borrow {$desc_new}{$opt_via} as {$kind_new} because previous closure requires unique access + .label = {$second_borrow_desc}borrow occurs here{$opt_via} + .occurs_label = {$container_name} construction occurs here{$old_opt_via} + .ends_label = borrow from closure ends here + +borrowck_cannot_return_ref_to_local = + cannot {$return_kind} {$reference} {$local} + .label = {$return_kind}s a {$reference} data owned by the current function + +borrowck_cannot_uniquely_borrow_by_one_closure = + closure requires unique access to {$desc_new} but {$noun_old} is already borrowed{$old_opt_via} + .label = {$container_name} construction occurs here{$opt_via} + .occurs_label = borrow occurs here{$old_opt_via} + .ends_label = borrow ends here + +borrowck_cannot_uniquely_borrow_by_two_closures = + two closures require unique access to {$desc -> + [value] value + *[other] {$desc} + } at the same time + .label = borrow from first closure ends here + .new_span_label = second closure is constructed here + +borrowck_cannot_use_static_lifetime_here = + cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type + +borrowck_cannot_use_when_mutably_borrowed = + cannot use {$desc -> + [value] value + *[other] {$desc} + } because it was mutably borrowed + .label = use of borrowed {$borrow_desc -> + [value] value + *[other] {$borrow_desc} + } + .borrow_span_label = {$borrow_desc -> + [value] value + *[other] {$borrow_desc} + } is borrowed here + borrowck_capture_immute = capture is immutable because of use here @@ -42,6 +213,17 @@ borrowck_capture_move = borrowck_capture_mut = capture is mutable because of use here +borrowck_closure_borrowing_outlive_function = + {$closure_kind} may outlive the current function, but it borrows {$borrowed_path}, which is owned by the current function + .label = may outlive borrowed value {$borrowed_path} + .path_label = {$borrowed_path} is borrowed here + +borrowck_closure_cannot_invoke_again = + closure cannot be invoked more than once because it moves the variable `{$place}` out of its environment + +borrowck_closure_cannot_move_again = + closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place}` out of its environment + borrowck_closure_inferred_mut = inferred to be a `FnMut` closure borrowck_closure_invoked_twice = @@ -50,18 +232,70 @@ borrowck_closure_invoked_twice = borrowck_closure_moved_twice = closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment +borrowck_closures_constructed_here = + closures are constructed here in different iterations of loop + +borrowck_consider_add_lifetime_bound = + consider adding the following bound: `{$fr_name}: {$outlived_fr_name}` + +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_borrow_type_contents = help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents +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_consider_move_expression_end_of_block = + 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_could_not_normalize = could not normalize `{$value}` borrowck_could_not_prove = could not prove `{$predicate}` +borrowck_data_moved_here = + data moved here + +borrowck_define_const_type = + defining constant type: {$type_name} + +borrowck_define_inline_constant_type = + defining inline constant type: {$type_name} + +borrowck_define_type = + defining type: {$type_name} + +borrowck_define_type_with_closure_args = + defining type: {$type_name} with closure args [ + {" "}{$subsets}, + ] + +borrowck_define_type_with_generator_args = + defining type: {$type_name} with generator args [ + {" "}{$subsets}, + ] + +borrowck_empty_label = {""} + +borrowck_expects_fn_not_fnmut = + expects `Fn` instead of `FnMut` + +borrowck_expects_fnmut_not_fn = + change this to accept `FnMut` instead of `Fn` + +borrowck_first_closure_constructed_here = + first closure is constructed here + borrowck_func_take_self_moved_place = `{$func}` takes ownership of the receiver `self`, which moves {$place_name} +borrowck_function_takes_self_ownership = + this function takes ownership of the receiver `self`, which moves {$place_name} + borrowck_generic_does_not_live_long_enough = `{$kind}` does not live long enough @@ -71,9 +305,27 @@ borrowck_higher_ranked_lifetime_error = borrowck_higher_ranked_subtype_error = higher-ranked subtype error +borrowck_in_this_closure = + in this closure + +borrowck_lifetime_appears_here_in_impl = + lifetime `{$rg_name}` appears in the `impl`'s {$location} + +borrowck_lifetime_appears_in_type = + lifetime `{$rg_name}` appears in the type {$type_name} + +borrowck_lifetime_appears_in_type_of = + lifetime `{$rg_name}` appears in the type of `{$upvar_name}` + borrowck_lifetime_constraints_error = lifetime may not live long enough +borrowck_modify_ty_methods_help = + to modify a `{$ty}`, use `.get_mut()`, `.insert()` or the entry API + +borrowck_move_borrowed = + cannot move out of `{$desc}` because it is borrowed + borrowck_move_out_place_here = {$place} is moved here @@ -129,6 +381,66 @@ borrowck_moved_due_to_usage_in_operator = *[false] operator } +borrowck_moved_var_cannot_copy = + move occurs because these variables have types that don't implement the `Copy` trait + +borrowck_mut_borrow_data_behind_const_pointer = + cannot borrow data in a `*const` pointer as mutable + +borrowck_mut_borrow_data_behind_deref = + cannot borrow data in {$name} as mutable + +borrowck_mut_borrow_data_behind_index = + cannot borrow data in an index of {$name} as mutable + +borrowck_mut_borrow_data_behind_ref = + cannot borrow data in a `&` reference as mutable + +borrowck_mut_borrow_place_declared_immute = + cannot borrow `{$place}` as mutable, as it is not declared as mutable + +borrowck_mut_borrow_place_in_pattern_guard_immute = + cannot borrow `{$place}` as mutable, as it is immutable for the pattern guard + +borrowck_mut_borrow_place_static = + cannot borrow immutable static item `{$place}` as mutable + +borrowck_mut_borrow_self_behind_const_pointer = + cannot borrow `{$place}` as mutable, as it is behind a `*const` pointer + +borrowck_mut_borrow_self_behind_deref = + cannot borrow `{$place}` as mutable, as it is behind {$name} + +borrowck_mut_borrow_self_behind_index = + cannot borrow `{$place}` as mutable, as it is behind an index of {$name} + +borrowck_mut_borrow_self_behind_ref = + cannot borrow `{$place}` as mutable, as it is behind a `&` reference + +borrowck_mut_borrow_self_in_fn = + cannot borrow `{$place}` as mutable, as it is a captured variable in a `Fn` closure + +borrowck_mut_borrow_symbol_declared_immute = + cannot borrow `{$place}` as mutable, as `{$name}` is not declared as mutable + +borrowck_mut_borrow_symbol_static = + cannot borrow `{$place}` as mutable, as `{$static_name}` is an immutable static item + +borrowck_mut_borrow_upvar_in_fn = + cannot borrow `{$place}` as mutable, as `Fn` closures cannot mutate their captured variables + +borrowck_mutably_borrow_multiply_loop_label = + {$is_place_empty -> + *[true] {$new_place_name} + [false] {$new_place_name} (via {$place}) + } was mutably borrowed here in the previous iteration of the loop{$place} + +borrowck_name_this_region = + let's call this `{$rg_name}` + +borrowck_non_defining_opaque_type = + non-defining opaque type use in defining scope + borrowck_opaque_type_non_generic_param = expected generic {$kind} parameter, found `{$ty}` .label = {STREQ($ty, "'static") -> @@ -136,6 +448,15 @@ borrowck_opaque_type_non_generic_param = *[other] this generic parameter must be used with a generic {$kind} parameter } +borrowck_outlive_constraint_need_borrow_for = + {$category}requires that {$desc} is borrowed for `{$region_name}` + +borrowck_outlive_constraint_need_borrow_lasts = + {$category}requires that `{$borrow_desc}` lasts for `{$region_name}` + +borrowck_outlive_constraint_need_borrow_lasts_for = + {$category}requires that {$borrow_desc} is borrowed for `{$region_name}` + borrowck_partial_var_move_by_use_in_closure = variable {$is_partial -> [true] partially moved @@ -148,6 +469,15 @@ borrowck_partial_var_move_by_use_in_coroutine = *[false] moved } due to use in coroutine +borrowck_path_does_not_live_long_enough = + {$path} does not live long enough + +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_return_fnmut = + change this to return `FnMut` instead of `Fn` + borrowck_returned_async_block_escaped = returns an `async` block that contains a reference to a captured variable, which then escapes the closure body @@ -155,7 +485,7 @@ borrowck_returned_closure_escaped = returns a closure that contains a reference to a captured variable, which then escapes the closure body borrowck_returned_lifetime_short = - {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}` + {$category}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}` borrowck_returned_lifetime_wrong = {$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}` @@ -177,18 +507,33 @@ borrowck_suggest_create_freash_reborrow = borrowck_suggest_iterate_over_slice = consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop +borrowck_thread_local_outlive_function = + thread-local variable borrowed past end of function + borrowck_ty_no_impl_copy = {$is_partial_move -> [true] partial move *[false] move } occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait +borrowck_type_parameter_not_used_in_trait_type_alias = + type parameter `{$ty}` is part of concrete type but not used in parameter list for the `impl Trait` type alias + +borrowck_upvar_need_mut_due_to_borrow = + calling `{$place}` requires mutable binding due to mutable borrow of `{$upvar}` + +borrowck_upvar_need_mut_due_to_mutation = + calling `{$place}` requires mutable binding due to possible mutation of `{$upvar}` + borrowck_use_due_to_use_closure = use occurs due to use in closure borrowck_use_due_to_use_coroutine = use occurs due to use in coroutine +borrowck_used_here_by_closure = + used here by closure + borrowck_used_impl_require_static = the used `impl` has a `'static` requirement @@ -199,15 +544,15 @@ borrowck_value_capture_here = } borrowck_value_moved_here = - value {$is_partial -> - [true] partially moved - *[false] moved + {$is_partial -> + [true] value partially + *[false] value } {$is_move_msg -> - [true] into closure here + [true] moved into closure + *[false] moved + } {$is_loop_message -> + [true] here, in previous iteration of loop *[false] here - }{$is_loop_message -> - [true] , in previous iteration of loop - *[false] {""} } borrowck_var_borrow_by_use_in_closure = @@ -261,3 +606,6 @@ borrowck_var_second_borrow_by_use_place_in_closure = borrowck_var_second_borrow_by_use_place_in_coroutine = second borrow occurs due to use of {$place} in coroutine + +borrowck_yield_type_is_type = + yield type is {$type_name} diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 429bcb74a8efc..bab49ced4dbed 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -5,6 +5,14 @@ use rustc_errors::{codes::*, struct_span_code_err, DiagCtxt, DiagnosticBuilder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; +use crate::{ + diagnostics::PlaceAndReason, + session_diagnostics::{ + AssignBorrowErr, AssignErr, BorrowAcrossCoroutineYield, BorrowAcrossDestructor, + InteriorDropMoveErr, MutBorrowErr, PathShortLive, UseMutBorrowErr, + }, +}; + impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { pub fn dcx(&self) -> &'tcx DiagCtxt { self.infcx.dcx() @@ -34,64 +42,49 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { 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}")) + self.dcx().create_err(UseMutBorrowErr { desc, borrow_desc, span, borrow_span }) } pub(crate) fn cannot_mutably_borrow_multiply( &self, new_loan_span: Span, - desc: &str, - opt_via: &str, + new_place_name: &str, + place: &str, old_loan_span: Span, - old_opt_via: &str, + old_place: &str, old_load_end_span: Option, ) -> 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 { + use crate::session_diagnostics::MutBorrowMulti::*; + let via = place.is_empty(); + self.dcx().create_err(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( + SameSpan { + new_place_name, + place, + old_place, + is_place_empty: via, 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"); + old_load_end_span, + eager_label: crate::session_diagnostics::MutMultiLoopLabel { + new_place_name, + place, + is_place_empty: via, + new_loan_span, + }, } } else { - err.span_label( - old_loan_span, - format!("first mutable borrow occurs here{}", via(old_opt_via)), - ); - err.span_label( + ChangedSpan { + new_place_name, + place, + old_place, + is_place_empty: via, + is_old_place_empty: old_place.is_empty(), 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"); + old_loan_span, + old_load_end_span, } - } - err + }) } pub(crate) fn cannot_uniquely_borrow_by_two_closures( @@ -101,26 +94,19 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_loan_span: Span, old_load_end_span: Option, ) -> 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", - ); + use crate::session_diagnostics::ClosureConstructLabel::*; + let (case, diff_span) = if old_loan_span == new_loan_span { + (Both { old_loan_span }, None) } 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 + (First { old_loan_span }, Some(new_loan_span)) + }; + self.dcx().create_err(crate::session_diagnostics::TwoClosuresUniquelyBorrowErr { + desc, + case, + new_loan_span, + old_load_end_span, + diff_span, + }) } pub(crate) fn cannot_uniquely_borrow_by_one_closure( @@ -134,24 +120,16 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_opt_via: &str, previous_end_span: Option, ) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_code_err!( - self.dcx(), + self.dcx().create_err(crate::session_diagnostics::ClosureUniquelyBorrowErr { new_loan_span, - E0500, - "closure requires unique access to {} but {} is already borrowed{}", + container_name, desc_new, + opt_via, + old_loan_span, 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 + previous_end_span, + }) } pub(crate) fn cannot_reborrow_already_uniquely_borrowed( @@ -166,24 +144,17 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { previous_end_span: Option, second_borrow_desc: &str, ) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_code_err!( - self.dcx(), + self.dcx().create_err(crate::session_diagnostics::ClosureReBorrowErr { new_loan_span, - E0501, - "cannot borrow {}{} as {} because previous closure requires unique access", + container_name, 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 + old_opt_via, + previous_end_span, + second_borrow_desc, + }) } pub(crate) fn cannot_reborrow_already_borrowed( @@ -198,39 +169,32 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { msg_old: &str, old_load_end_span: Option, ) -> 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(), - span, - E0502, - "cannot borrow {}{} as {} because {} is also borrowed as {}{}", + use crate::session_diagnostics::BorrowOccurLabel::*; + let via = |msg: &str| msg.is_empty(); + let (new_occur, old_occur) = if msg_new == "" { + // If `msg_new` is empty, then this isn't a borrow of a union field. + (Here { span, kind: kind_new }, Here { span: old_span, kind: kind_old }) + } else { + // If `msg_new` isn't empty, then this a borrow of a union field. + ( + HereOverlap { span, kind_new, msg_new, msg_old }, + HereVia { span: old_span, kind_old, is_msg_old_empty: via(msg_old), msg_old }, + ) + }; + self.dcx().create_err(crate::session_diagnostics::ReborrowBorrowedErr { desc_new, - via(msg_new), + is_msg_new_empty: via(msg_new), + 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 + is_msg_old_empty: via(msg_old), + msg_old, + span, + old_load_end_span, + new_occur, + old_occur, + }) } pub(crate) fn cannot_assign_to_borrowed( @@ -239,15 +203,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { borrow_span: Span, desc: &str, ) -> DiagnosticBuilder<'tcx> { - 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")) + self.dcx().create_err(AssignBorrowErr { desc, span, borrow_span }) } pub(crate) fn cannot_reassign_immutable( @@ -256,12 +212,78 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { desc: &str, is_arg: bool, ) -> DiagnosticBuilder<'tcx> { - 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) + use crate::session_diagnostics::ReassignImmut::*; + self.dcx().create_err(if is_arg { + Arg { span, place: desc } + } else { + Var { span, place: 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_assign( + &self, + span: Span, + path_and_reason: PlaceAndReason<'_>, + ) -> DiagnosticBuilder<'tcx> { + let diag = match path_and_reason { + PlaceAndReason::DeclaredImmute(place, name) => { + if let Some(name) = name { + AssignErr::SymbolDeclaredImmute { span, place, name } + } else { + AssignErr::PlaceDeclaredImmute { span, place } + } + } + PlaceAndReason::InPatternGuard(place) => AssignErr::PatternGuardImmute { span, place }, + PlaceAndReason::StaticItem(place, name) => { + if let Some(name) = name { + AssignErr::SymbolStatic { span, place, static_name: name } + } else { + AssignErr::PlaceStatic { span, place } + } + } + PlaceAndReason::UpvarCaptured(place) => AssignErr::UpvarInFn { span, place }, + PlaceAndReason::SelfCaptured(place) => AssignErr::CapturedInFn { span, place }, + PlaceAndReason::BehindPointer(place, pointer_ty, name) => { + if place.0.is_some() { + match pointer_ty { + crate::diagnostics::BorrowedContentSource::DerefRawPointer => { + AssignErr::PlaceBehindRawPointer { span, place } + } + crate::diagnostics::BorrowedContentSource::DerefMutableRef => { + unreachable!() + } + crate::diagnostics::BorrowedContentSource::DerefSharedRef => { + AssignErr::PlaceBehindSharedRef { span, place } + } + crate::diagnostics::BorrowedContentSource::OverloadedDeref(_) => { + AssignErr::PlaceBehindDeref { span, place, name } + } + crate::diagnostics::BorrowedContentSource::OverloadedIndex(_) => { + AssignErr::PlaceBehindIndex { span, place, name } + } + } + } else { + match pointer_ty { + crate::diagnostics::BorrowedContentSource::DerefRawPointer => { + AssignErr::DataBehindRawPointer { span } + } + crate::diagnostics::BorrowedContentSource::DerefMutableRef => { + unreachable!() + } + crate::diagnostics::BorrowedContentSource::DerefSharedRef => { + AssignErr::DataBehindSharedRef { span } + } + crate::diagnostics::BorrowedContentSource::OverloadedDeref(_) => { + AssignErr::DataBehindDeref { span, name } + } + crate::diagnostics::BorrowedContentSource::OverloadedIndex(_) => { + AssignErr::DataBehindIndex { span, name } + } + } + } + } + }; + self.dcx().create_err(diag) } pub(crate) fn cannot_move_out_of( @@ -308,14 +330,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { move_from_span: Span, container_ty: Ty<'_>, ) -> DiagnosticBuilder<'tcx> { - 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") + self.dcx().create_err(InteriorDropMoveErr { container_ty, move_from_span }) } pub(crate) fn cannot_act_on_moved_value( @@ -341,17 +356,69 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { pub(crate) fn cannot_borrow_path_as_mutable_because( &self, span: Span, - path: &str, - reason: &str, + path_and_reason: PlaceAndReason<'_>, ) -> DiagnosticBuilder<'tcx> { - struct_span_code_err!( - self.dcx(), - span, - E0596, - "cannot borrow {} as mutable{}", - path, - reason - ) + let diag = match path_and_reason { + PlaceAndReason::DeclaredImmute(place, name) => { + if let Some(name) = name { + MutBorrowErr::SymbolDeclaredImmute { span, place, name } + } else { + MutBorrowErr::PlaceDeclaredImmute { span, place } + } + } + PlaceAndReason::InPatternGuard(place) => { + MutBorrowErr::PatternGuardImmute { span, place } + } + PlaceAndReason::StaticItem(place, name) => { + if let Some(name) = name { + MutBorrowErr::SymbolStatic { span, place, static_name: name } + } else { + MutBorrowErr::PlaceStatic { span, place } + } + } + PlaceAndReason::UpvarCaptured(place) => MutBorrowErr::UpvarInFn { span, place }, + PlaceAndReason::SelfCaptured(place) => MutBorrowErr::CapturedInFn { span, place }, + PlaceAndReason::BehindPointer(place, pointer_ty, name) => { + if place.0.is_some() { + match pointer_ty { + crate::diagnostics::BorrowedContentSource::DerefRawPointer => { + MutBorrowErr::SelfBehindRawPointer { span, place } + } + crate::diagnostics::BorrowedContentSource::DerefSharedRef => { + MutBorrowErr::SelfBehindSharedRef { span, place } + } + crate::diagnostics::BorrowedContentSource::OverloadedDeref(_) => { + MutBorrowErr::SelfBehindDeref { span, place, name } + } + crate::diagnostics::BorrowedContentSource::OverloadedIndex(_) => { + MutBorrowErr::SelfBehindIndex { span, place, name } + } + crate::diagnostics::BorrowedContentSource::DerefMutableRef => { + unreachable!() + } + } + } else { + match pointer_ty { + crate::diagnostics::BorrowedContentSource::DerefRawPointer => { + MutBorrowErr::DataBehindRawPointer { span } + } + crate::diagnostics::BorrowedContentSource::DerefMutableRef => { + unreachable!() + } + crate::diagnostics::BorrowedContentSource::DerefSharedRef => { + MutBorrowErr::DataBehindSharedRef { span } + } + crate::diagnostics::BorrowedContentSource::OverloadedDeref(_) => { + MutBorrowErr::DataBehindDeref { span, name } + } + crate::diagnostics::BorrowedContentSource::OverloadedIndex(_) => { + MutBorrowErr::DataBehindIndex { span, name } + } + } + } + } + }; + self.dcx().create_err(diag) } pub(crate) fn cannot_mutate_in_immutable_section( @@ -381,25 +448,18 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { yield_span: Span, ) -> DiagnosticBuilder<'tcx> { let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind; - struct_span_code_err!( - self.dcx(), + self.dcx().create_err(BorrowAcrossCoroutineYield { span, - E0626, - "borrow may still be in use when {coroutine_kind:#} yields", - ) - .with_span_label(yield_span, "possible yield occurs here") + yield_span, + coroutine_kind: format!("{coroutine_kind:#}"), + }) } 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", - ) + self.dcx().create_err(BorrowAcrossDestructor { borrow_span }) } pub(crate) fn path_does_not_live_long_enough( @@ -407,7 +467,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, path: &str, ) -> DiagnosticBuilder<'tcx> { - struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,) + self.dcx().create_err(PathShortLive { path, span }) } pub(crate) fn cannot_return_reference_to_local( diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index e1509da913a56..ab3dd89e5e985 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1917,6 +1917,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as /// mutable (via `a.u.s.b`) [E0502] /// ``` + // FIXME(#100717): In the return value, the first three strings can contain untranslated text. pub(crate) fn describe_place_for_conflicting_borrow( &self, first_borrowed_place: Place<'tcx>, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index db0d69b6eaa09..345641f122d50 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -5,7 +5,7 @@ use crate::session_diagnostics::{ CaptureVarKind, CaptureVarPathUseCause, OnClosureNote, }; use itertools::Itertools; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, DiagnosticArgValue, DiagnosticBuilder, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::CoroutineKind; @@ -48,7 +48,7 @@ mod region_errors; pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo}; pub(crate) use move_errors::{IllegalMoveOriginKind, MoveError}; -pub(crate) use mutability_errors::AccessKind; +pub(crate) use mutability_errors::{AccessKind, PlaceAndReason}; pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder; pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; pub(crate) use region_name::{RegionName, RegionNameSource}; @@ -64,6 +64,18 @@ pub(super) struct DescribePlaceOpt { pub(super) struct IncludingTupleField(pub(super) bool); +#[derive(Debug)] +pub(super) struct DescribedPlace(pub(super) Option); + +impl IntoDiagnosticArg for DescribedPlace { + fn into_diagnostic_arg(self) -> DiagnosticArgValue { + match self.0 { + Some(descr) => descr.into_diagnostic_arg(), + None => "value".into_diagnostic_arg(), + } + } +} + impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure /// is moved after being invoked. @@ -175,6 +187,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } + pub(super) fn describe_place_typed(&self, place_ref: PlaceRef<'tcx>) -> DescribedPlace { + DescribedPlace(self.describe_place(place_ref)) + } + /// End-user visible description of `place` if one can be found. /// If the place is a temporary for instance, `None` will be returned. pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option { @@ -699,6 +715,7 @@ impl UseSpans<'_> { } } +#[derive(Clone, Copy, Debug)] pub(super) enum BorrowedContentSource<'tcx> { DerefRawPointer, DerefMutableRef, @@ -750,7 +767,7 @@ impl<'tcx> BorrowedContentSource<'tcx> { _ => None, }) .unwrap_or_else(|| format!("dereference of `{ty}`")), - BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{ty}`"), + BorrowedContentSource::OverloadedIndex(ty) => format!("`{ty}`"), } } diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 3478a73254a43..d007c137ab58a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -10,6 +10,7 @@ use rustc_span::{BytePos, ExpnKind, MacroKind, Span}; use crate::diagnostics::CapturedMessageOpt; use crate::diagnostics::{DescribePlaceOpt, UseSpans}; use crate::prefixes::PrefixSet; +use crate::session_diagnostics::AddMoveErr; use crate::MirBorrowckCtxt; #[derive(Debug)] @@ -584,9 +585,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let binding_span = bind_to.source_info.span; if j == 0 { - err.span_label(binding_span, "data moved here"); + err.subdiagnostic(self.dcx(), AddMoveErr::Here { binding_span }); } else { - err.span_label(binding_span, "...and here"); + err.subdiagnostic(self.dcx(), AddMoveErr::AndHere { binding_span }); } if binds_to.len() == 1 { @@ -604,10 +605,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } if binds_to.len() > 1 { - err.note( - "move occurs because these variables have types that don't implement the `Copy` \ - trait", - ); + err.subdiagnostic(self.dcx(), AddMoveErr::MovedNotCopy); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index b8257ba0adcc4..49997d5231984 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1,6 +1,5 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] - use hir::ExprKind; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -20,15 +19,34 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use crate::diagnostics::BorrowedContentSource; +use crate::session_diagnostics::{BorrowMutUpvarLable, FnMutBumpFn, OnModifyTy}; use crate::util::FindAssignments; use crate::MirBorrowckCtxt; +use super::DescribedPlace; + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(crate) enum AccessKind { MutableBorrow, Mutate, } +#[derive(Debug)] +pub(crate) enum PlaceAndReason<'a> { + // place, name + DeclaredImmute(DescribedPlace, Option), + // place + InPatternGuard(DescribedPlace), + // place, name + StaticItem(DescribedPlace, Option), + // place + UpvarCaptured(DescribedPlace), + // place + SelfCaptured(DescribedPlace), + // place, pointer_type, name + BehindPointer(DescribedPlace, BorrowedContentSource<'a>, String), +} + impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { pub(crate) fn report_mutability_error( &mut self, @@ -46,21 +64,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); let mut err; - let item_msg; - let reason; + let diagnostic: PlaceAndReason<'_>; let mut opt_source = None; - let access_place_desc = self.describe_any_place(access_place.as_ref()); - debug!("report_mutability_error: access_place_desc={:?}", access_place_desc); + let access_place_desc = self.describe_place_typed(access_place.as_ref()); match the_place_err { PlaceRef { local, projection: [] } => { - item_msg = access_place_desc; - if access_place.as_local().is_some() { - reason = ", as it is not declared as mutable".to_string(); + diagnostic = if access_place.as_local().is_some() { + PlaceAndReason::DeclaredImmute(access_place_desc, None) } else { let name = self.local_names[local].expect("immutable unnamed local"); - reason = format!(", as `{name}` is not declared as mutable"); - } + PlaceAndReason::DeclaredImmute(access_place_desc, Some(name.to_string())) + }; } PlaceRef { @@ -86,12 +101,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // If we deref an immutable ref then the suggestion here doesn't help. return; } else { - item_msg = access_place_desc; - if self.is_upvar_field_projection(access_place.as_ref()).is_some() { - reason = ", as it is not declared as mutable".to_string(); + diagnostic = if self.is_upvar_field_projection(access_place.as_ref()).is_some() + { + PlaceAndReason::DeclaredImmute(access_place_desc, None) } else { let name = self.upvars[upvar_index.index()].to_string(self.infcx.tcx); - reason = format!(", as `{name}` is not declared as mutable"); + PlaceAndReason::DeclaredImmute(access_place_desc, Some(name)) } } } @@ -99,21 +114,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { local, projection: [ProjectionElem::Deref] } if self.body.local_decls[local].is_ref_for_guard() => { - item_msg = access_place_desc; - reason = ", as it is immutable for the pattern guard".to_string(); + diagnostic = PlaceAndReason::InPatternGuard(access_place_desc) } PlaceRef { local, projection: [ProjectionElem::Deref] } if self.body.local_decls[local].is_ref_to_static() => { - if access_place.projection.len() == 1 { - item_msg = format!("immutable static item {access_place_desc}"); - reason = String::new(); + diagnostic = if access_place.projection.len() == 1 { + PlaceAndReason::StaticItem(access_place_desc, None) } else { - item_msg = access_place_desc; let local_info = self.body.local_decls[local].local_info(); if let LocalInfo::StaticRef { def_id, .. } = *local_info { let static_name = &self.infcx.tcx.item_name(def_id); - reason = format!(", as `{static_name}` is an immutable static item"); + PlaceAndReason::StaticItem(access_place_desc, Some(static_name.to_string())) } else { bug!("is_ref_to_static return true, but not ref to static?"); } @@ -124,34 +136,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { && proj_base.is_empty() && !self.upvars.is_empty() { - item_msg = access_place_desc; debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref()); debug_assert!(is_closure_like(the_place_err.ty(self.body, self.infcx.tcx).ty)); - reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() { - ", as it is a captured variable in a `Fn` closure".to_string() + diagnostic = if self.is_upvar_field_projection(access_place.as_ref()).is_some() + { + PlaceAndReason::SelfCaptured(access_place_desc) } else { - ", as `Fn` closures cannot mutate their captured variables".to_string() + PlaceAndReason::UpvarCaptured(access_place_desc) } } else { - let source = self.borrowed_content_source(PlaceRef { + let ptr_source = self.borrowed_content_source(PlaceRef { local: the_place_err.local, projection: proj_base, }); - let pointer_type = source.describe_for_immutable_place(self.infcx.tcx); - opt_source = Some(source); - if let Some(desc) = self.describe_place(access_place.as_ref()) { - item_msg = format!("`{desc}`"); - reason = match error_access { - AccessKind::Mutate => format!(", which is behind {pointer_type}"), - AccessKind::MutableBorrow => { - format!(", as it is behind {pointer_type}") - } - } - } else { - item_msg = format!("data in {pointer_type}"); - reason = String::new(); - } + let name = ptr_source.describe_for_immutable_place(self.infcx.tcx); + diagnostic = PlaceAndReason::BehindPointer( + self.describe_place_typed(access_place.as_ref()), + ptr_source, + name, + ); + opt_source = Some(ptr_source); } } @@ -170,8 +175,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } => bug!("Unexpected immutable place."), } - debug!("report_mutability_error: item_msg={:?}, reason={:?}", item_msg, reason); - // `act` and `acted_on` are strings that let us abstract over // the verbs used in some diagnostic messages. let act; @@ -180,9 +183,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut mut_error = None; let mut count = 1; + let access_diagnose_builder = |sp: Span| match error_access { + AccessKind::MutableBorrow => FnMutBumpFn::CannotBorrowMut { sp }, + AccessKind::Mutate => FnMutBumpFn::CannotAssign { sp }, + }; let span = match error_access { AccessKind::Mutate => { - err = self.cannot_assign(span, &(item_msg + &reason)); + err = self.cannot_assign(span, diagnostic); act = "assign"; acted_on = "written"; span @@ -212,19 +219,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } suggest = false; } else { - err = self.cannot_borrow_path_as_mutable_because( - borrow_span, - &item_msg, - &reason, - ); + err = + self.cannot_borrow_path_as_mutable_because(borrow_span, diagnostic); } } _ => { - err = self.cannot_borrow_path_as_mutable_because( - borrow_span, - &item_msg, - &reason, - ); + err = self.cannot_borrow_path_as_mutable_because(borrow_span, diagnostic); } } if suggest { @@ -245,8 +245,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } }; - debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on); - match the_place_err { // Suggest making an existing shared borrow in a struct definition a mutable borrow. // @@ -264,7 +262,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ProjectionElem::Deref, ], } => { - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(self.dcx(), access_diagnose_builder(span)); let place = Place::ty_from(local, proj_base, self.body, self.infcx.tcx); if let Some(span) = get_mut_span_in_struct_field(self.infcx.tcx, place.ty, *field) { @@ -286,7 +284,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) => { let decl = &self.body.local_decls[local]; - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(self.dcx(), access_diagnose_builder(span)); if let Some(mir::Statement { source_info, kind: @@ -371,7 +369,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { assert_eq!(local_decl.mutability, Mutability::Not); if count < 10 { - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(self.dcx(), access_diagnose_builder(span)); } if suggest { self.construct_mut_suggestion_for_local_binding_patterns(&mut err, local); @@ -393,7 +391,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let captured_place = self.upvars[upvar_index.index()]; - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(self.dcx(), access_diagnose_builder(span)); let upvar_hir_id = captured_place.get_root_variable(); @@ -448,7 +446,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .span_to_snippet(span) .is_ok_and(|snippet| snippet.starts_with("&mut ")) => { - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(self.dcx(), access_diagnose_builder(span)); err.span_suggestion( span, "try removing `&mut` here", @@ -460,7 +458,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { local, projection: [ProjectionElem::Deref] } if self.body.local_decls[local].is_ref_for_guard() => { - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(self.dcx(), access_diagnose_builder(span)); err.note( "variables bound in patterns are immutable until the end of the pattern guard", ); @@ -508,7 +506,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => { - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(self.dcx(), access_diagnose_builder(span)); match opt_source { Some(BorrowedContentSource::OverloadedDeref(ty)) => { @@ -529,7 +527,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } _ => { - err.span_label(span, format!("cannot {act}")); + err.subdiagnostic(self.dcx(), access_diagnose_builder(span)); } } @@ -653,9 +651,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut v = V { assign_span: span, err, ty, suggested: false }; v.visit_body(body); if !v.suggested { - err.help(format!( - "to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API", - )); + err.subdiagnostic(self.dcx(), OnModifyTy { ty }); } } } @@ -799,7 +795,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ) { let tables = tcx.typeck(closure_local_def_id); if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) { - let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base { + if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base { let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin); let root_hir_id = upvar_id.var_path.hir_id; // we have an origin for this closure kind starting at this root variable so it's safe to unwrap here @@ -811,7 +807,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .iter() .map(|proj| proj.kind) .collect::>(); - let mut capture_reason = String::new(); for captured_place in captured_places { let captured_place_kinds = captured_place .place @@ -823,14 +818,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &captured_place_kinds, &origin_projection, ) { + let place = self.describe_place(the_place_err).unwrap(); match captured_place.info.capture_kind { ty::UpvarCapture::ByRef( ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, ) => { - capture_reason = format!("mutable borrow of `{upvar}`"); + err.subdiagnostic( + self.dcx(), + BorrowMutUpvarLable::MutBorrow { span: *span, upvar, place }, + ); } ty::UpvarCapture::ByValue => { - capture_reason = format!("possible mutation of `{upvar}`"); + err.subdiagnostic( + self.dcx(), + BorrowMutUpvarLable::Mutation { span: *span, upvar, place }, + ); } _ => bug!("upvar `{upvar}` borrowed, but not mutably"), } @@ -996,9 +998,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _ => None, }; if let Some(span) = arg { - err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); - err.span_label(func.span, "expects `Fn` instead of `FnMut`"); - err.span_label(closure_span, "in this closure"); + err.subdiagnostic(self.dcx(), FnMutBumpFn::AcceptFnMut { span }); + err.subdiagnostic(self.dcx(), FnMutBumpFn::AcceptFn { span: func.span }); + err.subdiagnostic(self.dcx(), FnMutBumpFn::Here { span: closure_span }); look_at_return = false; } } @@ -1019,12 +1021,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { kind: hir::ImplItemKind::Fn(sig, _), .. }) => { - err.span_label(ident.span, ""); - err.span_label( - sig.decl.output.span(), - "change this to return `FnMut` instead of `Fn`", + err.subdiagnostic(self.dcx(), FnMutBumpFn::EmptyLabel { span: ident.span }); + err.subdiagnostic( + self.dcx(), + FnMutBumpFn::ReturnFnMut { span: sig.decl.output.span() }, ); - err.span_label(closure_span, "in this closure"); + err.subdiagnostic(self.dcx(), FnMutBumpFn::Here { span: closure_span }); } _ => {} } diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index b2c7a98142eec..9dcf5b6724ea6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -173,9 +173,13 @@ impl OutlivesSuggestionBuilder { if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name) && !matches!(outlived_fr_name.source, RegionNameSource::Static) { - diag.help(format!( - "consider adding the following bound: `{fr_name}: {outlived_fr_name}`", - )); + diag.subdiagnostic( + diag.dcx, + crate::session_diagnostics::OnLifetimeBound::Add { + fr_name: &fr_name, + outlived_fr_name: &outlived_fr_name, + }, + ); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 50d22881c3e61..b7d5e1ea5ab3e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -797,7 +797,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }, _ => LifetimeReturnCategoryErr::ShortReturn { span: *span, - category_desc: category.description(), + category: category.description(), free_region_name: &fr_name, outlived_fr_name, }, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index e228bef1139a6..465ec8847a8bd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use crate::session_diagnostics::RegionNameLabels; use crate::{universal_regions::DefiningTy, MirBorrowckCtxt}; /// A name for a particular region used in emitting diagnostics. This name could be a generated @@ -137,15 +138,18 @@ impl RegionName { RegionNameHighlight::MatchedAdtAndSegment(span), _, ) => { - diag.span_label(*span, format!("let's call this `{self}`")); + diag.subdiagnostic( + diag.dcx, + RegionNameLabels::NameRegion { span: *span, rg_name: self }, + ); } RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::Occluded( span, type_name, )) => { - diag.span_label( - *span, - format!("lifetime `{self}` appears in the type {type_name}"), + diag.subdiagnostic( + diag.dcx, + RegionNameLabels::LifetimeInType { span: *span, type_name, rg_name: self }, ); } RegionNameSource::AnonRegionFromOutput( @@ -160,9 +164,9 @@ impl RegionName { ); } RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => { - diag.span_label( - *span, - format!("lifetime `{self}` appears in the type of `{upvar_name}`"), + diag.subdiagnostic( + diag.dcx, + RegionNameLabels::LifetimeInTypeOf { span: *span, upvar_name, rg_name: self }, ); } RegionNameSource::AnonRegionFromOutput( @@ -172,12 +176,19 @@ impl RegionName { diag.span_label(*span, format!("return type{mir_description} is {type_name}")); } RegionNameSource::AnonRegionFromYieldTy(span, type_name) => { - diag.span_label(*span, format!("yield type is {type_name}")); + diag.subdiagnostic( + diag.dcx, + RegionNameLabels::YieldTypeIsTpye { span: *span, type_name }, + ); } RegionNameSource::AnonRegionFromImplSignature(span, location) => { - diag.span_label( - *span, - format!("lifetime `{self}` appears in the `impl`'s {location}"), + diag.subdiagnostic( + diag.dcx, + RegionNameLabels::LifetimeInImpl { + span: *span, + rg_name: self, + location: &location, + }, ); } RegionNameSource::Static => {} diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index a055ce95e8ef3..932db185b50f0 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -1,9 +1,9 @@ use rustc_errors::{codes::*, MultiSpan}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{GenericArg, Ty}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; -use crate::diagnostics::RegionName; +use crate::diagnostics::{DescribedPlace, RegionName}; #[derive(Diagnostic)] #[diag(borrowck_move_unsized, code = E0161)] @@ -122,7 +122,7 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> { ShortReturn { #[primary_span] span: Span, - category_desc: &'static str, + category: &'a str, free_region_name: &'a RegionName, outlived_fr_name: RegionName, }, @@ -461,3 +461,601 @@ pub(crate) struct SimdIntrinsicArgConst { pub arg: usize, pub intrinsic: String, } + +#[derive(Subdiagnostic)] +pub(crate) enum AddMoveErr { + #[label(borrowck_data_moved_here)] + Here { + #[primary_span] + binding_span: Span, + }, + #[label(borrowck_and_data_moved_here)] + AndHere { + #[primary_span] + binding_span: Span, + }, + #[note(borrowck_moved_var_cannot_copy)] + MovedNotCopy, +} + +#[derive(Subdiagnostic)] +pub(crate) enum OnLifetimeBound<'a> { + #[help(borrowck_consider_add_lifetime_bound)] + Add { fr_name: &'a RegionName, outlived_fr_name: &'a RegionName }, +} + +#[derive(Subdiagnostic)] +pub(crate) enum FnMutBumpFn { + #[label(borrowck_cannot_assign)] + CannotAssign { + #[primary_span] + sp: Span, + }, + #[label(borrowck_cannot_borrow_mut)] + CannotBorrowMut { + #[primary_span] + sp: Span, + }, + #[label(borrowck_expects_fnmut_not_fn)] + AcceptFnMut { + #[primary_span] + span: Span, + }, + #[label(borrowck_expects_fn_not_fnmut)] + AcceptFn { + #[primary_span] + span: Span, + }, + #[label(borrowck_empty_label)] + EmptyLabel { + #[primary_span] + span: Span, + }, + #[label(borrowck_in_this_closure)] + Here { + #[primary_span] + span: Span, + }, + #[label(borrowck_return_fnmut)] + ReturnFnMut { + #[primary_span] + span: Span, + }, +} + +#[derive(Subdiagnostic)] +pub(crate) enum RegionNameLabels<'a> { + #[label(borrowck_name_this_region)] + NameRegion { + #[primary_span] + span: Span, + rg_name: &'a RegionName, + }, + #[label(borrowck_lifetime_appears_in_type)] + LifetimeInType { + #[primary_span] + span: Span, + type_name: &'a Symbol, + rg_name: &'a RegionName, + }, + #[label(borrowck_lifetime_appears_in_type_of)] + LifetimeInTypeOf { + #[primary_span] + span: Span, + upvar_name: &'a Symbol, + rg_name: &'a RegionName, + }, + #[label(borrowck_yield_type_is_type)] + YieldTypeIsTpye { + #[primary_span] + span: Span, + type_name: &'a Symbol, + }, + #[label(borrowck_lifetime_appears_here_in_impl)] + LifetimeInImpl { + #[primary_span] + span: Span, + rg_name: &'a RegionName, + location: &'a str, + }, +} + +#[derive(Diagnostic)] +#[diag(borrowck_type_parameter_not_used_in_trait_type_alias)] +pub(crate) struct UnusedTypeParameter<'tcx> { + pub ty: Ty<'tcx>, + #[primary_span] + pub span: Span, +} + +#[derive(Subdiagnostic)] +pub(crate) enum DefiningTypeNote<'a> { + #[note(borrowck_define_type_with_closure_args)] + Closure { type_name: &'a str, subsets: &'a str }, + #[note(borrowck_define_type_with_generator_args)] + Generator { type_name: &'a str, subsets: &'a str }, + #[note(borrowck_define_type)] + FnDef { type_name: &'a str }, + #[note(borrowck_define_const_type)] + Const { type_name: &'a str }, + #[note(borrowck_define_inline_constant_type)] + InlineConst { type_name: &'a str }, +} + +#[derive(Diagnostic)] +#[diag(borrowck_borrowed_temporary_value_dropped, code = E0716)] +pub(crate) struct TemporaryDroppedErr { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(borrowck_thread_local_outlive_function, code = E0712)] +pub(crate) struct ThreadLocalOutliveErr { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(borrowck_closure_borrowing_outlive_function, code = E0373)] +pub(crate) struct ClosureVarOutliveErr<'a> { + pub closure_kind: &'a str, + pub borrowed_path: &'a str, + #[primary_span] + #[label] + pub closure_span: Span, + #[label(borrowck_path_label)] + pub capture_span: Span, +} + +#[derive(Diagnostic)] +#[diag(borrowck_cannot_return_ref_to_local, code = E0515)] +pub(crate) struct ReturnRefLocalErr<'a> { + pub return_kind: &'a str, + pub reference: &'a str, + pub local: &'a str, + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(borrowck_path_does_not_live_long_enough, code = E0597)] +pub(crate) struct PathShortLive<'a> { + pub path: &'a str, + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(borrowck_cannot_borrow_across_destructor, code = E0713)] +pub(crate) struct BorrowAcrossDestructor { + #[primary_span] + pub borrow_span: Span, +} + +#[derive(Diagnostic)] +#[diag(borrowck_cannot_borrow_across_coroutine_yield, code = E0626)] +pub(crate) struct BorrowAcrossCoroutineYield { + pub coroutine_kind: String, + #[primary_span] + pub span: Span, + #[label] + pub yield_span: Span, +} + +#[derive(Diagnostic)] +#[diag(borrowck_cannot_move_out_of_interior_of_drop, code = E0509)] +pub(crate) struct InteriorDropMoveErr<'a> { + pub container_ty: Ty<'a>, + #[primary_span] + #[label] + pub move_from_span: Span, +} + +#[derive(Diagnostic)] +#[diag(borrowck_cannot_assign_to_borrowed, code = E0506)] +pub(crate) struct AssignBorrowErr<'a> { + pub desc: &'a str, + #[primary_span] + #[label] + pub span: Span, + #[label(borrowck_borrow_here_label)] + pub borrow_span: Span, +} + +#[derive(Diagnostic)] +#[diag(borrowck_cannot_uniquely_borrow_by_two_closures, code = E0524)] +pub(crate) struct TwoClosuresUniquelyBorrowErr<'a> { + pub desc: &'a str, + #[primary_span] + pub new_loan_span: Span, + #[label] + pub old_load_end_span: Option, + #[label(borrowck_new_span_label)] + pub diff_span: Option, + #[subdiagnostic] + pub case: ClosureConstructLabel, +} + +#[derive(Subdiagnostic)] +pub(crate) enum ClosureConstructLabel { + #[label(borrowck_first_closure_constructed_here)] + First { + #[primary_span] + old_loan_span: Span, + }, + #[label(borrowck_closures_constructed_here)] + Both { + #[primary_span] + old_loan_span: Span, + }, +} + +#[derive(Diagnostic)] +#[diag(borrowck_cannot_use_when_mutably_borrowed, code = E0503)] +pub(crate) struct UseMutBorrowErr<'a> { + pub desc: &'a str, + pub borrow_desc: &'a str, + #[primary_span] + #[label] + pub span: Span, + #[label(borrowck_borrow_span_label)] + pub borrow_span: Span, +} + +#[derive(Diagnostic)] +pub(crate) enum MutBorrowMulti<'a> { + #[diag(borrowck_cannot_mutably_borrow_multiply_same_span, code = E0499)] + SameSpan { + new_place_name: &'a str, + place: &'a str, + old_place: &'a str, + is_place_empty: bool, + #[primary_span] + new_loan_span: Span, + #[label] + old_load_end_span: Option, + #[subdiagnostic] + eager_label: MutMultiLoopLabel<'a>, + }, + #[diag(borrowck_cannot_mutably_borrow_multiply, code = E0499)] + ChangedSpan { + new_place_name: &'a str, + place: &'a str, + old_place: &'a str, + is_place_empty: bool, + is_old_place_empty: bool, + #[primary_span] + #[label(borrowck_second_mut_borrow_label)] + new_loan_span: Span, + #[label] + old_loan_span: Span, + #[label(borrowck_first_mut_end_label)] + old_load_end_span: Option, + }, +} + +#[derive(Subdiagnostic)] +#[label(borrowck_mutably_borrow_multiply_loop_label)] +pub(crate) struct MutMultiLoopLabel<'a> { + pub new_place_name: &'a str, + pub place: &'a str, + pub is_place_empty: bool, + #[primary_span] + pub new_loan_span: Span, +} + +#[derive(Diagnostic)] +#[diag(borrowck_cannot_uniquely_borrow_by_one_closure, code = E0500)] +pub(crate) struct ClosureUniquelyBorrowErr<'a> { + #[primary_span] + #[label] + pub new_loan_span: Span, + pub container_name: &'a str, + pub desc_new: &'a str, + pub opt_via: &'a str, + #[label(borrowck_occurs_label)] + pub old_loan_span: Span, + pub noun_old: &'a str, + pub old_opt_via: &'a str, + #[label(borrowck_ends_label)] + pub previous_end_span: Option, +} + +#[derive(Diagnostic)] +#[diag(borrowck_cannot_reborrow_already_uniquely_borrowed, code = E0501)] +pub(crate) struct ClosureReBorrowErr<'a> { + #[primary_span] + #[label] + pub new_loan_span: Span, + pub container_name: &'a str, + pub desc_new: &'a str, + pub opt_via: &'a str, + pub kind_new: &'a str, + #[label(borrowck_occurs_label)] + pub old_loan_span: Span, + pub old_opt_via: &'a str, + #[label(borrowck_ends_label)] + pub previous_end_span: Option, + pub second_borrow_desc: &'a str, +} + +#[derive(Subdiagnostic)] +pub(crate) enum BorrowOccurLabel<'a> { + #[label(borrowck_borrow_occurs_here)] + Here { + #[primary_span] + span: Span, + kind: &'a str, + }, + #[label(borrowck_borrow_occurs_here_overlap)] + HereOverlap { + #[primary_span] + span: Span, + kind_new: &'a str, + msg_new: &'a str, + msg_old: &'a str, + }, + #[label(borrowck_borrow_occurs_here_via)] + HereVia { + #[primary_span] + span: Span, + kind_old: &'a str, + is_msg_old_empty: bool, + msg_old: &'a str, + }, +} + +#[derive(Diagnostic)] +#[diag(borrowck_cannot_reborrow_already_borrowed, code = E0502)] +pub(crate) struct ReborrowBorrowedErr<'a> { + pub desc_new: &'a str, + pub is_msg_new_empty: bool, + pub msg_new: &'a str, + pub kind_new: &'a str, + pub noun_old: &'a str, + pub kind_old: &'a str, + pub is_msg_old_empty: bool, + pub msg_old: &'a str, + #[primary_span] + pub span: Span, + #[label] + pub old_load_end_span: Option, + #[subdiagnostic] + pub new_occur: BorrowOccurLabel<'a>, + #[subdiagnostic] + pub old_occur: BorrowOccurLabel<'a>, +} + +#[derive(Diagnostic)] +pub(crate) enum ReassignImmut<'a> { + #[diag(borrowck_cannot_reassign_immutable_arg, code = E0384)] + Arg { + #[primary_span] + span: Span, + place: &'a str, + }, + #[diag(borrowck_cannot_reassign_immutable_var, code = E0384)] + Var { + #[primary_span] + span: Span, + place: &'a str, + }, +} + +#[derive(Subdiagnostic)] +#[help(borrowck_modify_ty_methods_help)] +pub(crate) struct OnModifyTy<'tcx> { + pub ty: Ty<'tcx>, +} + +#[derive(Subdiagnostic)] +pub(crate) enum BorrowMutUpvarLable { + #[label(borrowck_upvar_need_mut_due_to_borrow)] + MutBorrow { + #[primary_span] + span: Span, + upvar: String, + place: String, + }, + #[label(borrowck_upvar_need_mut_due_to_mutation)] + Mutation { + #[primary_span] + span: Span, + upvar: String, + place: String, + }, +} + +#[derive(Diagnostic)] +pub(crate) enum MutBorrowErr { + #[diag(borrowck_mut_borrow_place_declared_immute, code = E0596)] + PlaceDeclaredImmute { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_mut_borrow_symbol_declared_immute, code = E0596)] + SymbolDeclaredImmute { + #[primary_span] + span: Span, + place: DescribedPlace, + name: String, + }, + #[diag(borrowck_mut_borrow_place_in_pattern_guard_immute, code = E0596)] + PatternGuardImmute { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_mut_borrow_symbol_static, code = E0596)] + SymbolStatic { + #[primary_span] + span: Span, + place: DescribedPlace, + static_name: String, + }, + #[diag(borrowck_mut_borrow_place_static, code = E0596)] + PlaceStatic { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_mut_borrow_self_in_fn, code = E0596)] + CapturedInFn { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_mut_borrow_upvar_in_fn, code = E0596)] + UpvarInFn { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_mut_borrow_self_behind_const_pointer, code = E0596)] + SelfBehindRawPointer { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_mut_borrow_self_behind_ref, code = E0596)] + SelfBehindSharedRef { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_mut_borrow_self_behind_deref, code = E0596)] + SelfBehindDeref { + #[primary_span] + span: Span, + place: DescribedPlace, + name: String, + }, + #[diag(borrowck_mut_borrow_self_behind_index, code = E0596)] + SelfBehindIndex { + #[primary_span] + span: Span, + place: DescribedPlace, + name: String, + }, + #[diag(borrowck_mut_borrow_data_behind_const_pointer, code = E0596)] + DataBehindRawPointer { + #[primary_span] + span: Span, + }, + #[diag(borrowck_mut_borrow_data_behind_ref, code = E0596)] + DataBehindSharedRef { + #[primary_span] + span: Span, + }, + #[diag(borrowck_mut_borrow_data_behind_deref, code = E0596)] + DataBehindDeref { + #[primary_span] + span: Span, + name: String, + }, + #[diag(borrowck_mut_borrow_data_behind_index, code = E0596)] + DataBehindIndex { + #[primary_span] + span: Span, + name: String, + }, +} + +#[derive(Diagnostic)] +pub(crate) enum AssignErr { + #[diag(borrowck_assign_place_declared_immute, code = E0594)] + PlaceDeclaredImmute { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_assign_symbol_declared_immute, code = E0594)] + SymbolDeclaredImmute { + #[primary_span] + span: Span, + place: DescribedPlace, + name: String, + }, + #[diag(borrowck_assign_place_in_pattern_guard_immute, code = E0594)] + PatternGuardImmute { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_assign_symbol_static, code = E0594)] + SymbolStatic { + #[primary_span] + span: Span, + place: DescribedPlace, + static_name: String, + }, + #[diag(borrowck_assign_place_static, code = E0594)] + PlaceStatic { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_assign_place_in_fn, code = E0594)] + CapturedInFn { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_assign_upvar_in_fn, code = E0594)] + UpvarInFn { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_assign_place_behind_const_pointer, code = E0594)] + PlaceBehindRawPointer { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_assign_place_behind_ref, code = E0594)] + PlaceBehindSharedRef { + #[primary_span] + span: Span, + place: DescribedPlace, + }, + #[diag(borrowck_assign_place_behind_deref, code = E0594)] + PlaceBehindDeref { + #[primary_span] + span: Span, + place: DescribedPlace, + name: String, + }, + #[diag(borrowck_assign_place_behind_index, code = E0594)] + PlaceBehindIndex { + #[primary_span] + span: Span, + place: DescribedPlace, + name: String, + }, + #[diag(borrowck_assign_data_behind_const_pointer, code = E0594)] + DataBehindRawPointer { + #[primary_span] + span: Span, + }, + #[diag(borrowck_assign_data_behind_ref, code = E0594)] + DataBehindSharedRef { + #[primary_span] + span: Span, + }, + #[diag(borrowck_assign_data_behind_deref, code = E0594)] + DataBehindDeref { + #[primary_span] + span: Span, + name: String, + }, + #[diag(borrowck_assign_data_behind_index, code = E0594)] + DataBehindIndex { + #[primary_span] + span: Span, + name: String, + }, +} diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index e743948103467..56a53e193cb1a 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -32,6 +32,7 @@ use rustc_span::Symbol; use std::iter; use crate::renumber::RegionCtxt; +use crate::session_diagnostics::DefiningTypeNote; use crate::BorrowckInferCtxt; #[derive(Debug)] @@ -352,11 +353,13 @@ impl<'tcx> UniversalRegions<'tcx> { .map(|arg| arg.to_string()) .collect::>() ); - err.note(format!( - "defining type: {} with closure args [\n {},\n]", - tcx.def_path_str_with_args(def_id, args), - v.join(",\n "), - )); + err.subdiagnostic( + tcx.dcx(), + DefiningTypeNote::Closure { + type_name: &tcx.def_path_str_with_args(def_id, args), + subsets: &v.join(",\n "), + }, + ); // FIXME: It'd be nice to print the late-bound regions // here, but unfortunately these wind up stored into @@ -377,11 +380,13 @@ impl<'tcx> UniversalRegions<'tcx> { .map(|arg| arg.to_string()) .collect::>() ); - err.note(format!( - "defining type: {} with coroutine args [\n {},\n]", - tcx.def_path_str_with_args(def_id, args), - v.join(",\n "), - )); + err.subdiagnostic( + tcx.dcx(), + DefiningTypeNote::Generator { + type_name: &tcx.def_path_str_with_args(def_id, &args), + subsets: &v.join(",\n "), + }, + ); // FIXME: As above, we'd like to print out the region // `r` but doing so is not stable across architectures @@ -391,19 +396,28 @@ impl<'tcx> UniversalRegions<'tcx> { }); } DefiningTy::FnDef(def_id, args) => { - err.note(format!("defining type: {}", tcx.def_path_str_with_args(def_id, args),)); + err.subdiagnostic( + tcx.dcx(), + DefiningTypeNote::FnDef { + type_name: &tcx.def_path_str_with_args(def_id, &args), + }, + ); } DefiningTy::Const(def_id, args) => { - err.note(format!( - "defining constant type: {}", - tcx.def_path_str_with_args(def_id, args), - )); + err.subdiagnostic( + tcx.dcx(), + DefiningTypeNote::Const { + type_name: &tcx.def_path_str_with_args(def_id, &args), + }, + ); } DefiningTy::InlineConst(def_id, args) => { - err.note(format!( - "defining inline constant type: {}", - tcx.def_path_str_with_args(def_id, args), - )); + err.subdiagnostic( + tcx.dcx(), + DefiningTypeNote::InlineConst { + type_name: &tcx.def_path_str_with_args(def_id, &args), + }, + ); } } }