]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_borrowck/src/used_muts.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / compiler / rustc_borrowck / src / used_muts.rs
CommitLineData
487cf647
FG
1#![deny(rustc::untranslatable_diagnostic)]
2#![deny(rustc::diagnostic_outside_of_impl)]
353b0b11 3use rustc_data_structures::fx::FxIndexSet;
ba9703b0 4use rustc_middle::mir::visit::{PlaceContext, Visitor};
f035d41b
XL
5use rustc_middle::mir::{
6 Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind,
7};
8faf50e0 8
c295e0f8 9use crate::MirBorrowckCtxt;
8faf50e0 10
dc9dc135 11impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
a1dfa0c6
XL
12 /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes
13 /// of the `unused_mut` lint.
14 ///
15 /// `temporary_used_locals` should contain locals that were found to be temporary, mutable and
16 /// used from borrow checking. This function looks for assignments into these locals from
17 /// user-declared locals and adds those user-defined locals to the `used_mut` set. This can
18 /// occur due to a rare case involving upvars in closures.
19 ///
20 /// `never_initialized_mut_locals` should contain the set of user-declared mutable locals
21 /// (not arguments) that have not already been marked as being used.
22 /// This function then looks for assignments from statements or the terminator into the locals
23 /// from this set and removes them from the set. This leaves only those locals that have not
24 /// been assigned to - this set is used as a proxy for locals that were not initialized due to
25 /// unreachable code. These locals are then considered "used" to silence the lint for them.
26 /// See #55344 for context.
923072b8 27 pub(crate) fn gather_used_muts(
a1dfa0c6 28 &mut self,
353b0b11
FG
29 temporary_used_locals: FxIndexSet<Local>,
30 mut never_initialized_mut_locals: FxIndexSet<Local>,
a1dfa0c6
XL
31 ) {
32 {
33 let mut visitor = GatherUsedMutsVisitor {
34 temporary_used_locals,
35 never_initialized_mut_locals: &mut never_initialized_mut_locals,
36 mbcx: self,
37 };
4b012472 38 visitor.visit_body(visitor.mbcx.body);
a1dfa0c6
XL
39 }
40
41 // Take the union of the existed `used_mut` set with those variables we've found were
42 // never initialized.
43 debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals);
44 self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect();
8faf50e0
XL
45 }
46}
47
a1dfa0c6
XL
48/// MIR visitor for collecting used mutable variables.
49/// The 'visit lifetime represents the duration of the MIR walk.
dc9dc135 50struct GatherUsedMutsVisitor<'visit, 'cx, 'tcx> {
353b0b11
FG
51 temporary_used_locals: FxIndexSet<Local>,
52 never_initialized_mut_locals: &'visit mut FxIndexSet<Local>,
dc9dc135 53 mbcx: &'visit mut MirBorrowckCtxt<'cx, 'tcx>,
8faf50e0
XL
54}
55
dc9dc135 56impl GatherUsedMutsVisitor<'_, '_, '_> {
ba9703b0 57 fn remove_never_initialized_mut_locals(&mut self, into: Place<'_>) {
dc9dc135
XL
58 // Remove any locals that we found were initialized from the
59 // `never_initialized_mut_locals` set. At the end, the only remaining locals will
60 // be those that were never initialized - we will consider those as being used as
61 // they will either have been removed by unreachable code optimizations; or linted
62 // as unused variables.
dfeec247 63 self.never_initialized_mut_locals.remove(&into.local);
dc9dc135
XL
64 }
65}
66
67impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tcx> {
f035d41b
XL
68 fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
69 debug!("visit_terminator: terminator={:?}", terminator);
70 match &terminator.kind {
923072b8
FG
71 TerminatorKind::Call { destination, .. } => {
72 self.remove_never_initialized_mut_locals(*destination);
dfeec247 73 }
dfeec247 74 _ => {}
a1dfa0c6 75 }
f035d41b
XL
76
77 self.super_terminator(terminator, location);
a1dfa0c6
XL
78 }
79
f035d41b 80 fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
ba9703b0
XL
81 if let StatementKind::Assign(box (into, _)) = &statement.kind {
82 debug!(
83 "visit_statement: statement={:?} local={:?} \
dfeec247 84 never_initialized_mut_locals={:?}",
ba9703b0
XL
85 statement, into.local, self.never_initialized_mut_locals
86 );
87 self.remove_never_initialized_mut_locals(*into);
a1dfa0c6 88 }
f035d41b
XL
89
90 self.super_statement(statement, location);
a1dfa0c6
XL
91 }
92
064997fb
FG
93 fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) {
94 if place_context.is_place_assignment() && self.temporary_used_locals.contains(&local) {
8faf50e0
XL
95 // Propagate the Local assigned at this Location as a used mutable local variable
96 for moi in &self.mbcx.move_data.loc_map[location] {
97 let mpi = &self.mbcx.move_data.moves[*moi].path;
98 let path = &self.mbcx.move_data.move_paths[*mpi];
99 debug!(
100 "assignment of {:?} to {:?}, adding {:?} to used mutable set",
101 path.place, local, path.place
102 );
e74abb32 103 if let Some(user_local) = path.place.as_local() {
8faf50e0
XL
104 self.mbcx.used_mut.insert(user_local);
105 }
106 }
107 }
108 }
109}