Skip to content

Lazy init diagnostics-only local_names in borrowck #142882

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ impl<'tcx> BorrowExplanation<'tcx> {
) {
let tcx = cx.infcx.tcx;
let body = cx.body;
let local_names = &cx.local_names;

if let Some(span) = borrow_span {
let def_id = body.source.def_id();
Expand Down Expand Up @@ -220,7 +219,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
_ => ("destructor", format!("type `{}`", local_decl.ty)),
};

match local_names[dropped_local] {
match cx.local_name(dropped_local) {
Some(local_name) if !local_decl.from_compiler_desugaring() => {
let message = format!(
"{borrow_desc}borrow might be used here, when `{local_name}` is dropped \
Expand Down Expand Up @@ -670,10 +669,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {

Some(Cause::DropVar(local, location)) => {
let mut should_note_order = false;
if self.local_names[local].is_some()
if self.local_name(local).is_some()
&& let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place
&& let Some(borrowed_local) = place.as_local()
&& self.local_names[borrowed_local].is_some()
&& self.local_name(borrowed_local).is_some()
&& local != borrowed_local
{
should_note_order = true;
Expand Down Expand Up @@ -748,7 +747,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
Operand::Copy(place) | Operand::Move(place) => {
if let Some(l) = place.as_local() {
let local_decl = &self.body.local_decls[l];
if self.local_names[l].is_none() {
if self.local_name(l).is_none() {
local_decl.source_info.span
} else {
span
Expand Down Expand Up @@ -793,7 +792,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
Operand::Copy(place) | Operand::Move(place) => {
if let Some(l) = place.as_local() {
let local_decl = &self.body.local_decls[l];
if self.local_names[l].is_none() {
if self.local_name(l).is_none() {
local_decl.source_info.span
} else {
span
Expand Down
43 changes: 39 additions & 4 deletions compiler/rustc_borrowck/src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::{self as hir, CoroutineKind, LangItem};
use rustc_index::IndexSlice;
use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::{BoundRegionConversionTime, NllRegionVariableOrigin};
use rustc_infer::traits::SelectionError;
use rustc_middle::bug;
use rustc_middle::mir::{
AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo,
LocalKind, Location, Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement,
StatementKind, Terminator, TerminatorKind, find_self_call,
StatementKind, Terminator, TerminatorKind, VarDebugInfoContents, find_self_call,
};
use rustc_middle::ty::print::Print;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex};
use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Spanned;
Expand Down Expand Up @@ -190,6 +190,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
) -> Option<&(PlaceRef<'tcx>, Diag<'infcx>)> {
self.diags_buffer.buffered_move_errors.get(move_out_indices)
}

/// Uses `body.var_debug_info` to find the symbol
fn local_name(&self, index: Local) -> Option<Symbol> {
*self.local_names().get(index)?
}

fn local_names(&self) -> &IndexSlice<Local, Option<Symbol>> {
self.local_names.get_or_init(|| {
let mut local_names = IndexVec::from_elem(None, &self.body.local_decls);
for var_debug_info in &self.body.var_debug_info {
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
if let Some(local) = place.as_local() {
if let Some(prev_name) = local_names[local]
&& var_debug_info.name != prev_name
{
span_bug!(
var_debug_info.source_info.span,
"local {:?} has many names (`{}` vs `{}`)",
local,
prev_name,
var_debug_info.name
);
}
local_names[local] = Some(var_debug_info.name);
}
}
}
local_names
})
}
}

impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
Expand Down Expand Up @@ -430,7 +460,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// a name, or its name was generated by the compiler, then `Err` is returned
fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
let decl = &self.body.local_decls[local];
match self.local_names[local] {
match self.local_name(local) {
Some(name) if !decl.from_compiler_desugaring() => {
buf.push_str(name.as_str());
Ok(())
Expand Down Expand Up @@ -1500,4 +1530,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}
}

/// Skip over locals that begin with an underscore or have no name
pub(crate) fn local_excluded_from_unused_mut_lint(&self, index: Local) -> bool {
self.local_name(index).is_none_or(|name| name.as_str().starts_with('_'))
}
}
10 changes: 7 additions & 3 deletions compiler/rustc_borrowck/src/diagnostics/move_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,11 +465,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {

if let PlaceRef { local, projection: [] } = deref_base {
let decl = &self.body.local_decls[local];
let local_name = self.local_name(local).map(|sym| format!("`{sym}`"));
if decl.is_ref_for_guard() {
return self
.cannot_move_out_of(
span,
&format!("`{}` in pattern guard", self.local_names[local].unwrap()),
&format!(
"{} in pattern guard",
local_name.as_deref().unwrap_or("the place")
),
)
.with_note(
"variables bound in patterns cannot be moved from \
Expand Down Expand Up @@ -825,7 +829,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}

if binds_to.len() == 1 {
let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
let place_desc = self.local_name(*local).map(|sym| format!("`{sym}`"));

if let Some(expr) = self.find_expr(binding_span) {
self.suggest_cloning(err, bind_to.ty, expr, None);
Expand All @@ -834,7 +838,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty: bind_to.ty,
place: place_desc,
place: place_desc.as_deref().unwrap_or("the place"),
span: binding_span,
});
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
if access_place.as_local().is_some() {
reason = ", as it is not declared as mutable".to_string();
} else {
let name = self.local_names[local].expect("immutable unnamed local");
let name = self.local_name(local).expect("immutable unnamed local");
reason = format!(", as `{name}` is not declared as mutable");
}
}
Expand Down Expand Up @@ -285,7 +285,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
.body
.local_decls
.get(local)
.is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) =>
.is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_name(local))) =>
{
let decl = &self.body.local_decls[local];
err.span_label(span, format!("cannot {act}"));
Expand Down Expand Up @@ -481,7 +481,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let (pointer_sigil, pointer_desc) =
if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };

match self.local_names[local] {
match self.local_name(local) {
Some(name) if !local_decl.from_compiler_desugaring() => {
err.span_label(
span,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,14 +664,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
self.infcx.tcx,
self.body,
&self.local_names,
&self.local_names(),
&self.upvars,
errci.fr,
);
let outlived_fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
self.infcx.tcx,
self.body,
&self.local_names,
&self.local_names(),
&self.upvars,
errci.outlived_fr,
);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/region_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
[implicit_inputs + argument_index];
let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
self.body,
&self.local_names,
self.local_names(),
argument_index,
);

Expand Down Expand Up @@ -973,7 +973,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
{
let (arg_name, arg_span) = self.regioncx.get_argument_name_and_span_for_region(
self.body,
&self.local_names,
self.local_names(),
arg_index,
);
let region_name = self.synthesize_region_name();
Expand Down
30 changes: 5 additions & 25 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// tidy-alphabetical-end

use std::borrow::Cow;
use std::cell::RefCell;
use std::cell::{OnceCell, RefCell};
use std::marker::PhantomData;
use std::ops::{ControlFlow, Deref};

Expand Down Expand Up @@ -391,7 +391,7 @@ fn do_mir_borrowck<'tcx>(
used_mut_upvars: SmallVec::new(),
borrow_set: &borrow_set,
upvars: &[],
local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
local_names: OnceCell::from(IndexVec::from_elem(None, &promoted_body.local_decls)),
region_names: RefCell::default(),
next_region_name: RefCell::new(1),
polonius_output: None,
Expand All @@ -414,26 +414,6 @@ fn do_mir_borrowck<'tcx>(
promoted_mbcx.report_move_errors();
}

let mut local_names = IndexVec::from_elem(None, &body.local_decls);
for var_debug_info in &body.var_debug_info {
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
if let Some(local) = place.as_local() {
if let Some(prev_name) = local_names[local]
&& var_debug_info.name != prev_name
{
span_bug!(
var_debug_info.source_info.span,
"local {:?} has many names (`{}` vs `{}`)",
local,
prev_name,
var_debug_info.name
);
}
local_names[local] = Some(var_debug_info.name);
}
}
}

let mut mbcx = MirBorrowckCtxt {
root_cx,
infcx: &infcx,
Expand All @@ -450,7 +430,7 @@ fn do_mir_borrowck<'tcx>(
used_mut_upvars: SmallVec::new(),
borrow_set: &borrow_set,
upvars: tcx.closure_captures(def),
local_names,
local_names: OnceCell::new(),
region_names: RefCell::default(),
next_region_name: RefCell::new(1),
move_errors: Vec::new(),
Expand Down Expand Up @@ -682,7 +662,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],

/// Names of local (user) variables (extracted from `var_debug_info`).
local_names: IndexVec<Local, Option<Symbol>>,
local_names: OnceCell<IndexVec<Local, Option<Symbol>>>,

/// Record the region names generated for each region in the given
/// MIR def so that we can reuse them later in help/error messages.
Expand Down Expand Up @@ -2610,7 +2590,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
};

// Skip over locals that begin with an underscore or have no name
if self.local_names[local].is_none_or(|name| name.as_str().starts_with('_')) {
if self.local_excluded_from_unused_mut_lint(local) {
continue;
}

Expand Down
Loading