1 use crate::util::elaborate_drops::DropFlagState;
2 use rustc::mir::{self, Body, Location};
3 use rustc::ty::{self, TyCtxt};
5 use super::indexes::MovePathIndex;
6 use super::move_paths::{InitKind, LookupResult, MoveData};
7 use super::MoveDataParamEnv;
9 pub fn move_path_children_matching<'tcx, F>(
10 move_data: &MoveData<'tcx>,
13 ) -> Option<MovePathIndex>
15 F: FnMut(&mir::PlaceElem<'tcx>) -> bool,
17 let mut next_child = move_data.move_paths[path].first_child;
18 while let Some(child_index) = next_child {
19 let move_path_children = &move_data.move_paths[child_index];
20 if let Some(elem) = move_path_children.place.projection.last() {
22 return Some(child_index);
25 next_child = move_path_children.next_sibling;
31 /// When enumerating the child fragments of a path, don't recurse into
32 /// paths (1.) past arrays, slices, and pointers, nor (2.) into a type
33 /// that implements `Drop`.
35 /// Places behind references or arrays are not tracked by elaboration
36 /// and are always assumed to be initialized when accessible. As
37 /// references and indexes can be reseated, trying to track them can
38 /// only lead to trouble.
40 /// Places behind ADT's with a Drop impl are not tracked by
41 /// elaboration since they can never have a drop-flag state that
42 /// differs from that of the parent with the Drop impl.
44 /// In both cases, the contents can only be accessed if and only if
45 /// their parents are initialized. This implies for example that there
46 /// is no need to maintain separate drop flags to track such state.
48 // FIXME: we have to do something for moving slice patterns.
49 fn place_contents_drop_state_cannot_differ<'tcx>(
52 place: &mir::Place<'tcx>,
54 let ty = place.ty(body, tcx).ty;
58 "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
63 ty::Slice(..) | ty::Ref(..) | ty::RawPtr(..) => {
65 "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
70 ty::Adt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => {
72 "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} Drop => true",
81 pub(crate) fn on_lookup_result_bits<'tcx, F>(
84 move_data: &MoveData<'tcx>,
85 lookup_result: LookupResult,
88 F: FnMut(MovePathIndex),
91 LookupResult::Parent(..) => {
92 // access to untracked value - do not touch children
94 LookupResult::Exact(e) => on_all_children_bits(tcx, body, move_data, e, each_child),
98 pub(crate) fn on_all_children_bits<'tcx, F>(
101 move_data: &MoveData<'tcx>,
102 move_path_index: MovePathIndex,
105 F: FnMut(MovePathIndex),
107 fn is_terminal_path<'tcx>(
110 move_data: &MoveData<'tcx>,
113 place_contents_drop_state_cannot_differ(tcx, body, &move_data.move_paths[path].place)
116 fn on_all_children_bits<'tcx, F>(
119 move_data: &MoveData<'tcx>,
120 move_path_index: MovePathIndex,
123 F: FnMut(MovePathIndex),
125 each_child(move_path_index);
127 if is_terminal_path(tcx, body, move_data, move_path_index) {
131 let mut next_child_index = move_data.move_paths[move_path_index].first_child;
132 while let Some(child_index) = next_child_index {
133 on_all_children_bits(tcx, body, move_data, child_index, each_child);
134 next_child_index = move_data.move_paths[child_index].next_sibling;
137 on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child);
140 pub(crate) fn on_all_drop_children_bits<'tcx, F>(
143 ctxt: &MoveDataParamEnv<'tcx>,
147 F: FnMut(MovePathIndex),
149 on_all_children_bits(tcx, body, &ctxt.move_data, path, |child| {
150 let place = &ctxt.move_data.move_paths[path].place;
151 let ty = place.ty(body, tcx).ty;
152 debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty);
154 let erased_ty = tcx.erase_regions(&ty);
155 if erased_ty.needs_drop(tcx, ctxt.param_env) {
158 debug!("on_all_drop_children_bits - skipping")
163 pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>(
166 ctxt: &MoveDataParamEnv<'tcx>,
169 F: FnMut(MovePathIndex, DropFlagState),
171 let move_data = &ctxt.move_data;
172 for arg in body.args_iter() {
173 let place = mir::Place::from(arg);
174 let lookup_result = move_data.rev_lookup.find(place.as_ref());
175 on_lookup_result_bits(tcx, body, move_data, lookup_result, |mpi| {
176 callback(mpi, DropFlagState::Present)
181 pub(crate) fn drop_flag_effects_for_location<'tcx, F>(
184 ctxt: &MoveDataParamEnv<'tcx>,
188 F: FnMut(MovePathIndex, DropFlagState),
190 let move_data = &ctxt.move_data;
191 debug!("drop_flag_effects_for_location({:?})", loc);
193 // first, move out of the RHS
194 for mi in &move_data.loc_map[loc] {
195 let path = mi.move_path_index(move_data);
196 debug!("moving out of path {:?}", move_data.move_paths[path]);
198 on_all_children_bits(tcx, body, move_data, path, |mpi| callback(mpi, DropFlagState::Absent))
201 debug!("drop_flag_effects: assignment for location({:?})", loc);
203 for_location_inits(tcx, body, move_data, loc, |mpi| callback(mpi, DropFlagState::Present));
206 pub(crate) fn for_location_inits<'tcx, F>(
209 move_data: &MoveData<'tcx>,
213 F: FnMut(MovePathIndex),
215 for ii in &move_data.init_loc_map[loc] {
216 let init = move_data.inits[*ii];
219 let path = init.path;
221 on_all_children_bits(tcx, body, move_data, path, &mut callback)
223 InitKind::Shallow => {
227 InitKind::NonPanicPathOnly => (),