1 use rustc::mir::{self, Mir, 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::PlaceProjection<'tcx>) -> bool
15 let mut next_child = move_data.move_paths[path].first_child;
16 while let Some(child_index) = next_child {
17 match move_data.move_paths[child_index].place {
18 mir::Place::Projection(ref proj) => {
20 return Some(child_index)
25 next_child = move_data.move_paths[child_index].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<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
51 place: &mir::Place<'tcx>) -> bool {
52 let ty = place.ty(mir, 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<'a, 'gcx, 'tcx, F>(
76 tcx: TyCtxt<'a, 'gcx, 'tcx>,
78 move_data: &MoveData<'tcx>,
79 lookup_result: LookupResult,
81 where F: FnMut(MovePathIndex)
84 LookupResult::Parent(..) => {
85 // access to untracked value - do not touch children
87 LookupResult::Exact(e) => {
88 on_all_children_bits(tcx, mir, move_data, e, each_child)
93 pub(crate) fn on_all_children_bits<'a, 'gcx, 'tcx, F>(
94 tcx: TyCtxt<'a, 'gcx, 'tcx>,
96 move_data: &MoveData<'tcx>,
97 move_path_index: MovePathIndex,
99 where F: FnMut(MovePathIndex)
101 fn is_terminal_path<'a, 'gcx, 'tcx>(
102 tcx: TyCtxt<'a, 'gcx, 'tcx>,
104 move_data: &MoveData<'tcx>,
105 path: MovePathIndex) -> bool
107 place_contents_drop_state_cannot_differ(
108 tcx, mir, &move_data.move_paths[path].place)
111 fn on_all_children_bits<'a, 'gcx, 'tcx, F>(
112 tcx: TyCtxt<'a, 'gcx, 'tcx>,
114 move_data: &MoveData<'tcx>,
115 move_path_index: MovePathIndex,
117 where F: FnMut(MovePathIndex)
119 each_child(move_path_index);
121 if is_terminal_path(tcx, mir, move_data, move_path_index) {
125 let mut next_child_index = move_data.move_paths[move_path_index].first_child;
126 while let Some(child_index) = next_child_index {
127 on_all_children_bits(tcx, mir, move_data, child_index, each_child);
128 next_child_index = move_data.move_paths[child_index].next_sibling;
131 on_all_children_bits(tcx, mir, move_data, move_path_index, &mut each_child);
134 pub(crate) fn on_all_drop_children_bits<'a, 'gcx, 'tcx, F>(
135 tcx: TyCtxt<'a, 'gcx, 'tcx>,
137 ctxt: &MoveDataParamEnv<'gcx, 'tcx>,
140 where F: FnMut(MovePathIndex)
142 on_all_children_bits(tcx, mir, &ctxt.move_data, path, |child| {
143 let place = &ctxt.move_data.move_paths[path].place;
144 let ty = place.ty(mir, tcx).ty;
145 debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty);
147 let gcx = tcx.global_tcx();
148 let erased_ty = gcx.lift(&tcx.erase_regions(&ty)).unwrap();
149 if erased_ty.needs_drop(gcx, ctxt.param_env) {
152 debug!("on_all_drop_children_bits - skipping")
157 pub(crate) fn drop_flag_effects_for_function_entry<'a, 'gcx, 'tcx, F>(
158 tcx: TyCtxt<'a, 'gcx, 'tcx>,
160 ctxt: &MoveDataParamEnv<'gcx, 'tcx>,
162 where F: FnMut(MovePathIndex, DropFlagState)
164 let move_data = &ctxt.move_data;
165 for arg in mir.args_iter() {
166 let place = mir::Place::Base(mir::PlaceBase::Local(arg));
167 let lookup_result = move_data.rev_lookup.find(&place);
168 on_lookup_result_bits(tcx, mir, move_data,
170 |mpi| callback(mpi, DropFlagState::Present));
174 pub(crate) fn drop_flag_effects_for_location<'a, 'gcx, 'tcx, F>(
175 tcx: TyCtxt<'a, 'gcx, 'tcx>,
177 ctxt: &MoveDataParamEnv<'gcx, 'tcx>,
180 where F: FnMut(MovePathIndex, DropFlagState)
182 let move_data = &ctxt.move_data;
183 debug!("drop_flag_effects_for_location({:?})", loc);
185 // first, move out of the RHS
186 for mi in &move_data.loc_map[loc] {
187 let path = mi.move_path_index(move_data);
188 debug!("moving out of path {:?}", move_data.move_paths[path]);
190 on_all_children_bits(tcx, mir, move_data,
192 |mpi| callback(mpi, DropFlagState::Absent))
195 debug!("drop_flag_effects: assignment for location({:?})", loc);
202 |mpi| callback(mpi, DropFlagState::Present)
206 pub(crate) fn for_location_inits<'a, 'gcx, 'tcx, F>(
207 tcx: TyCtxt<'a, 'gcx, 'tcx>,
209 move_data: &MoveData<'tcx>,
212 where F: FnMut(MovePathIndex)
214 for ii in &move_data.init_loc_map[loc] {
215 let init = move_data.inits[*ii];
218 let path = init.path;
220 on_all_children_bits(tcx, mir, move_data,
224 InitKind::Shallow => {
228 InitKind::NonPanicPathOnly => (),