1use rustc_abi::VariantIdx;
2use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind};
3use tracing::debug;
4
5use super::move_paths::{InitKind, LookupResult, MoveData, MovePathIndex};
6
7#[derive(Debug, PartialEq, Eq, Copy, Clone)]
9pub enum DropFlagState {
10 Present,
12
13 Absent,
16}
17
18impl DropFlagState {
19 pub fn value(self) -> bool {
20 match self {
21 DropFlagState::Present => true,
22 DropFlagState::Absent => false,
23 }
24 }
25}
26
27pub fn move_path_children_matching<'tcx, F>(
28 move_data: &MoveData<'tcx>,
29 path: MovePathIndex,
30 mut cond: F,
31) -> Option<MovePathIndex>
32where
33 F: FnMut(mir::PlaceElem<'tcx>) -> bool,
34{
35 let mut next_child = move_data.move_paths[path].first_child;
36 while let Some(child_index) = next_child {
37 let move_path_children = &move_data.move_paths[child_index];
38 if let Some(&elem) = move_path_children.place.projection.last() {
39 if cond(elem) {
40 return Some(child_index);
41 }
42 }
43 next_child = move_path_children.next_sibling;
44 }
45
46 None
47}
48
49pub fn on_lookup_result_bits<'tcx, F>(
50 move_data: &MoveData<'tcx>,
51 lookup_result: LookupResult,
52 each_child: F,
53) where
54 F: FnMut(MovePathIndex),
55{
56 match lookup_result {
57 LookupResult::Parent(..) => {
58 }
60 LookupResult::Exact(e) => on_all_children_bits(move_data, e, each_child),
61 }
62}
63
64pub fn on_all_children_bits<'tcx, F>(
65 move_data: &MoveData<'tcx>,
66 move_path_index: MovePathIndex,
67 mut each_child: F,
68) where
69 F: FnMut(MovePathIndex),
70{
71 fn on_all_children_bits<'tcx, F>(
72 move_data: &MoveData<'tcx>,
73 move_path_index: MovePathIndex,
74 each_child: &mut F,
75 ) where
76 F: FnMut(MovePathIndex),
77 {
78 each_child(move_path_index);
79
80 let mut next_child_index = move_data.move_paths[move_path_index].first_child;
81 while let Some(child_index) = next_child_index {
82 on_all_children_bits(move_data, child_index, each_child);
83 next_child_index = move_data.move_paths[child_index].next_sibling;
84 }
85 }
86 on_all_children_bits(move_data, move_path_index, &mut each_child);
87}
88
89pub fn drop_flag_effects_for_function_entry<'tcx, F>(
90 body: &Body<'tcx>,
91 move_data: &MoveData<'tcx>,
92 mut callback: F,
93) where
94 F: FnMut(MovePathIndex, DropFlagState),
95{
96 for arg in body.args_iter() {
97 let place = mir::Place::from(arg);
98 let lookup_result = move_data.rev_lookup.find(place.as_ref());
99 on_lookup_result_bits(move_data, lookup_result, |mpi| {
100 callback(mpi, DropFlagState::Present)
101 });
102 }
103}
104
105pub fn drop_flag_effects_for_location<'tcx, F>(
106 body: &Body<'tcx>,
107 move_data: &MoveData<'tcx>,
108 loc: Location,
109 mut callback: F,
110) where
111 F: FnMut(MovePathIndex, DropFlagState),
112{
113 debug!("drop_flag_effects_for_location({:?})", loc);
114
115 for mi in &move_data.loc_map[loc] {
117 let path = mi.move_path_index(move_data);
118 debug!("moving out of path {:?}", move_data.move_paths[path]);
119
120 on_all_children_bits(move_data, path, |mpi| callback(mpi, DropFlagState::Absent))
121 }
122
123 if let Some(Terminator { kind: TerminatorKind::Drop { place, .. }, .. }) =
125 body.stmt_at(loc).right()
126 {
127 if let LookupResult::Exact(mpi) = move_data.rev_lookup.find(place.as_ref()) {
128 on_all_children_bits(move_data, mpi, |mpi| callback(mpi, DropFlagState::Absent))
129 }
130 }
131
132 debug!("drop_flag_effects: assignment for location({:?})", loc);
133
134 for_location_inits(move_data, loc, |mpi| callback(mpi, DropFlagState::Present));
135}
136
137fn for_location_inits<'tcx, F>(move_data: &MoveData<'tcx>, loc: Location, mut callback: F)
138where
139 F: FnMut(MovePathIndex),
140{
141 for ii in &move_data.init_loc_map[loc] {
142 let init = move_data.inits[*ii];
143 match init.kind {
144 InitKind::Deep => {
145 let path = init.path;
146
147 on_all_children_bits(move_data, path, &mut callback)
148 }
149 InitKind::Shallow => {
150 let mpi = init.path;
151 callback(mpi);
152 }
153 InitKind::NonPanicPathOnly => (),
154 }
155 }
156}
157
158pub(crate) fn on_all_inactive_variants<'tcx>(
164 move_data: &MoveData<'tcx>,
165 enum_place: mir::Place<'tcx>,
166 active_variant: VariantIdx,
167 mut handle_inactive_variant: impl FnMut(MovePathIndex),
168) {
169 let LookupResult::Exact(enum_mpi) = move_data.rev_lookup.find(enum_place.as_ref()) else {
170 return;
171 };
172
173 let enum_path = &move_data.move_paths[enum_mpi];
174 for (variant_mpi, variant_path) in enum_path.children(&move_data.move_paths) {
175 let (downcast, base_proj) = variant_path.place.projection.split_last().unwrap();
179 assert_eq!(enum_place.projection.len(), base_proj.len());
180
181 let mir::ProjectionElem::Downcast(_, variant_idx) = *downcast else {
182 unreachable!();
183 };
184
185 if variant_idx != active_variant {
186 on_all_children_bits(move_data, variant_mpi, |mpi| handle_inactive_variant(mpi));
187 }
188 }
189}