1 use rustc::mir::{self, Body, Location};
2 use rustc::ty::{self, TyCtxt};
3 use crate::util::elaborate_drops::DropFlagState;
5 use super::{MoveDataParamEnv};
6 use super::indexes::MovePathIndex;
7 use super::move_paths::{MoveData, LookupResult, InitKind};
9 pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>,
12 -> Option<MovePathIndex>
13 where F: FnMut(&mir::PlaceElem<'tcx>) -> bool
15 let mut next_child = move_data.move_paths[path].first_child;
16 while let Some(child_index) = next_child {
17 let move_path_children = &move_data.move_paths[child_index];
18 if let Some(elem) = move_path_children.place.projection.last() {
20 return Some(child_index)
23 next_child = move_path_children.next_sibling;
29 /// When enumerating the child fragments of a path, don't recurse into
30 /// paths (1.) past arrays, slices, and pointers, nor (2.) into a type
31 /// that implements `Drop`.
33 /// Places behind references or arrays are not tracked by elaboration
34 /// and are always assumed to be initialized when accessible. As
35 /// references and indexes can be reseated, trying to track them can
36 /// only lead to trouble.
38 /// Places behind ADT's with a Drop impl are not tracked by
39 /// elaboration since they can never have a drop-flag state that
40 /// differs from that of the parent with the Drop impl.
42 /// In both cases, the contents can only be accessed if and only if
43 /// their parents are initialized. This implies for example that there
44 /// is no need to maintain separate drop flags to track such state.
46 // FIXME: we have to do something for moving slice patterns.
47 fn place_contents_drop_state_cannot_differ<'tcx>(
50 place: &mir::Place<'tcx>,
52 let ty = place.ty(body, tcx).ty;
55 debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
59 ty::Slice(..) | ty::Ref(..) | ty::RawPtr(..) => {
60 debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
64 ty::Adt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => {
65 debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} Drop => true",
75 pub(crate) fn on_lookup_result_bits<'tcx, F>(
78 move_data: &MoveData<'tcx>,
79 lookup_result: LookupResult,
82 F: FnMut(MovePathIndex),
85 LookupResult::Parent(..) => {
86 // access to untracked value - do not touch children
88 LookupResult::Exact(e) => {
89 on_all_children_bits(tcx, body, move_data, e, each_child)
94 pub(crate) fn on_all_children_bits<'tcx, F>(
97 move_data: &MoveData<'tcx>,
98 move_path_index: MovePathIndex,
101 F: FnMut(MovePathIndex),
103 fn is_terminal_path<'tcx>(
106 move_data: &MoveData<'tcx>,
109 place_contents_drop_state_cannot_differ(
110 tcx, body, &move_data.move_paths[path].place)
113 fn on_all_children_bits<'tcx, F>(
116 move_data: &MoveData<'tcx>,
117 move_path_index: MovePathIndex,
120 F: FnMut(MovePathIndex),
122 each_child(move_path_index);
124 if is_terminal_path(tcx, body, move_data, move_path_index) {
128 let mut next_child_index = move_data.move_paths[move_path_index].first_child;
129 while let Some(child_index) = next_child_index {
130 on_all_children_bits(tcx, body, move_data, child_index, each_child);
131 next_child_index = move_data.move_paths[child_index].next_sibling;
134 on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child);
137 pub(crate) fn on_all_drop_children_bits<'tcx, F>(
140 ctxt: &MoveDataParamEnv<'tcx>,
144 F: FnMut(MovePathIndex),
146 on_all_children_bits(tcx, body, &ctxt.move_data, path, |child| {
147 let place = &ctxt.move_data.move_paths[path].place;
148 let ty = place.ty(body, tcx).ty;
149 debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty);
151 let gcx = tcx.global_tcx();
152 let erased_ty = tcx.erase_regions(&ty);
153 if erased_ty.needs_drop(gcx, ctxt.param_env) {
156 debug!("on_all_drop_children_bits - skipping")
161 pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>(
164 ctxt: &MoveDataParamEnv<'tcx>,
167 F: FnMut(MovePathIndex, DropFlagState),
169 let move_data = &ctxt.move_data;
170 for arg in body.args_iter() {
171 let place = mir::Place::from(arg);
172 let lookup_result = move_data.rev_lookup.find(place.as_ref());
173 on_lookup_result_bits(tcx, body, move_data,
175 |mpi| callback(mpi, DropFlagState::Present));
179 pub(crate) fn drop_flag_effects_for_location<'tcx, F>(
182 ctxt: &MoveDataParamEnv<'tcx>,
186 F: FnMut(MovePathIndex, DropFlagState),
188 let move_data = &ctxt.move_data;
189 debug!("drop_flag_effects_for_location({:?})", loc);
191 // first, move out of the RHS
192 for mi in &move_data.loc_map[loc] {
193 let path = mi.move_path_index(move_data);
194 debug!("moving out of path {:?}", move_data.move_paths[path]);
196 on_all_children_bits(tcx, body, move_data,
198 |mpi| callback(mpi, DropFlagState::Absent))
201 debug!("drop_flag_effects: assignment for location({:?})", loc);
208 |mpi| callback(mpi, DropFlagState::Present)
212 pub(crate) fn for_location_inits<'tcx, F>(
215 move_data: &MoveData<'tcx>,
219 F: FnMut(MovePathIndex),
221 for ii in &move_data.init_loc_map[loc] {
222 let init = move_data.inits[*ii];
225 let path = init.path;
227 on_all_children_bits(tcx, body, move_data,
231 InitKind::Shallow => {
235 InitKind::NonPanicPathOnly => (),