1use rustc_data_structures::fx::FxIndexSet;
2use rustc_middle::mir::visit::{PlaceContext, Visitor};
3use rustc_middle::mir::{
4Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind,
5};
6use tracing::debug;
78use crate::MirBorrowckCtxt;
910impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
11/// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes
12 /// of the `unused_mut` lint.
13 ///
14 /// `temporary_used_locals` should contain locals that were found to be temporary, mutable and
15 /// used from borrow checking. This function looks for assignments into these locals from
16 /// user-declared locals and adds those user-defined locals to the `used_mut` set. This can
17 /// occur due to a rare case involving upvars in closures.
18 ///
19 /// `never_initialized_mut_locals` should contain the set of user-declared mutable locals
20 /// (not arguments) that have not already been marked as being used.
21 /// This function then looks for assignments from statements or the terminator into the locals
22 /// from this set and removes them from the set. This leaves only those locals that have not
23 /// been assigned to - this set is used as a proxy for locals that were not initialized due to
24 /// unreachable code. These locals are then considered "used" to silence the lint for them.
25 /// See #55344 for context.
26pub(crate) fn gather_used_muts(
27&mut self,
28 temporary_used_locals: FxIndexSet<Local>,
29mut never_initialized_mut_locals: FxIndexSet<Local>,
30 ) {
31 {
32let mut visitor = GatherUsedMutsVisitor {
33temporary_used_locals,
34 never_initialized_mut_locals: &mut never_initialized_mut_locals,
35 mbcx: self,
36 };
37visitor.visit_body(visitor.mbcx.body);
38 }
3940// Take the union of the existed `used_mut` set with those variables we've found were
41 // never initialized.
42{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/used_muts.rs:42",
"rustc_borrowck::used_muts", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/used_muts.rs"),
::tracing_core::__macro_support::Option::Some(42u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::used_muts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("gather_used_muts: never_initialized_mut_locals={0:?}",
never_initialized_mut_locals) as &dyn Value))])
});
} else { ; }
};debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals);
43self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect();
44 }
45}
4647/// MIR visitor for collecting used mutable variables.
48/// The 'visit lifetime represents the duration of the MIR walk.
49struct GatherUsedMutsVisitor<'a, 'b, 'infcx, 'tcx> {
50 temporary_used_locals: FxIndexSet<Local>,
51 never_initialized_mut_locals: &'a mut FxIndexSet<Local>,
52 mbcx: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
53}
5455impl GatherUsedMutsVisitor<'_, '_, '_, '_> {
56fn remove_never_initialized_mut_locals(&mut self, into: Place<'_>) {
57// Remove any locals that we found were initialized from the
58 // `never_initialized_mut_locals` set. At the end, the only remaining locals will
59 // be those that were never initialized - we will consider those as being used as
60 // they will either have been removed by unreachable code optimizations; or linted
61 // as unused variables.
62 // FIXME(#120456) - is `swap_remove` correct?
63self.never_initialized_mut_locals.swap_remove(&into.local);
64 }
65}
6667impl<'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'_, '_, '_, 'tcx> {
68fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
69{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/used_muts.rs:69",
"rustc_borrowck::used_muts", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/used_muts.rs"),
::tracing_core::__macro_support::Option::Some(69u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::used_muts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("visit_terminator: terminator={0:?}",
terminator) as &dyn Value))])
});
} else { ; }
};debug!("visit_terminator: terminator={:?}", terminator);
70match &terminator.kind {
71 TerminatorKind::Call { destination, .. } => {
72self.remove_never_initialized_mut_locals(*destination);
73 }
74_ => {}
75 }
7677self.super_terminator(terminator, location);
78 }
7980fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
81if let StatementKind::Assign(box (into, _)) = &statement.kind {
82{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/used_muts.rs:82",
"rustc_borrowck::used_muts", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/used_muts.rs"),
::tracing_core::__macro_support::Option::Some(82u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::used_muts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("visit_statement: statement={0:?} local={1:?} never_initialized_mut_locals={2:?}",
statement, into.local, self.never_initialized_mut_locals) as
&dyn Value))])
});
} else { ; }
};debug!(
83"visit_statement: statement={:?} local={:?} \
84 never_initialized_mut_locals={:?}",
85 statement, into.local, self.never_initialized_mut_locals
86 );
87self.remove_never_initialized_mut_locals(*into);
88 }
8990self.super_statement(statement, location);
91 }
9293fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) {
94if place_context.is_place_assignment() && self.temporary_used_locals.contains(&local) {
95// Propagate the Local assigned at this Location as a used mutable local variable
96for moi in &self.mbcx.move_data.loc_map[location] {
97let mpi = &self.mbcx.move_data.moves[*moi].path;
98let path = &self.mbcx.move_data.move_paths[*mpi];
99{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/used_muts.rs:99",
"rustc_borrowck::used_muts", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/used_muts.rs"),
::tracing_core::__macro_support::Option::Some(99u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::used_muts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("assignment of {0:?} to {1:?}, adding {2:?} to used mutable set",
path.place, local, path.place) as &dyn Value))])
});
} else { ; }
};debug!(
100"assignment of {:?} to {:?}, adding {:?} to used mutable set",
101 path.place, local, path.place
102 );
103if let Some(user_local) = path.place.as_local() {
104self.mbcx.used_mut.insert(user_local);
105 }
106 }
107 }
108 }
109}