| use rustc::mir::{self, Body, Location}; |
| use rustc::ty::{self, TyCtxt}; |
| use crate::util::elaborate_drops::DropFlagState; |
| |
| use super::{MoveDataParamEnv}; |
| use super::indexes::MovePathIndex; |
| use super::move_paths::{MoveData, LookupResult, InitKind}; |
| |
| pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, |
| path: MovePathIndex, |
| mut cond: F) |
| -> Option<MovePathIndex> |
| where F: FnMut(&mir::PlaceElem<'tcx>) -> bool |
| { |
| let mut next_child = move_data.move_paths[path].first_child; |
| while let Some(child_index) = next_child { |
| let move_path_children = &move_data.move_paths[child_index]; |
| if let Some(elem) = move_path_children.place.projection.last() { |
| if cond(elem) { |
| return Some(child_index) |
| } |
| } |
| next_child = move_path_children.next_sibling; |
| } |
| |
| None |
| } |
| |
| /// When enumerating the child fragments of a path, don't recurse into |
| /// paths (1.) past arrays, slices, and pointers, nor (2.) into a type |
| /// that implements `Drop`. |
| /// |
| /// Places behind references or arrays are not tracked by elaboration |
| /// and are always assumed to be initialized when accessible. As |
| /// references and indexes can be reseated, trying to track them can |
| /// only lead to trouble. |
| /// |
| /// Places behind ADT's with a Drop impl are not tracked by |
| /// elaboration since they can never have a drop-flag state that |
| /// differs from that of the parent with the Drop impl. |
| /// |
| /// In both cases, the contents can only be accessed if and only if |
| /// their parents are initialized. This implies for example that there |
| /// is no need to maintain separate drop flags to track such state. |
| // |
| // FIXME: we have to do something for moving slice patterns. |
| fn place_contents_drop_state_cannot_differ<'tcx>( |
| tcx: TyCtxt<'tcx>, |
| body: &Body<'tcx>, |
| place: &mir::Place<'tcx>, |
| ) -> bool { |
| let ty = place.ty(body, tcx).ty; |
| match ty.kind { |
| ty::Array(..) => { |
| debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false", |
| place, ty); |
| false |
| } |
| ty::Slice(..) | ty::Ref(..) | ty::RawPtr(..) => { |
| debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true", |
| place, ty); |
| true |
| } |
| ty::Adt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => { |
| debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} Drop => true", |
| place, ty); |
| true |
| } |
| _ => { |
| false |
| } |
| } |
| } |
| |
| pub(crate) fn on_lookup_result_bits<'tcx, F>( |
| tcx: TyCtxt<'tcx>, |
| body: &Body<'tcx>, |
| move_data: &MoveData<'tcx>, |
| lookup_result: LookupResult, |
| each_child: F, |
| ) where |
| F: FnMut(MovePathIndex), |
| { |
| match lookup_result { |
| LookupResult::Parent(..) => { |
| // access to untracked value - do not touch children |
| } |
| LookupResult::Exact(e) => { |
| on_all_children_bits(tcx, body, move_data, e, each_child) |
| } |
| } |
| } |
| |
| pub(crate) fn on_all_children_bits<'tcx, F>( |
| tcx: TyCtxt<'tcx>, |
| body: &Body<'tcx>, |
| move_data: &MoveData<'tcx>, |
| move_path_index: MovePathIndex, |
| mut each_child: F, |
| ) where |
| F: FnMut(MovePathIndex), |
| { |
| fn is_terminal_path<'tcx>( |
| tcx: TyCtxt<'tcx>, |
| body: &Body<'tcx>, |
| move_data: &MoveData<'tcx>, |
| path: MovePathIndex, |
| ) -> bool { |
| place_contents_drop_state_cannot_differ( |
| tcx, body, &move_data.move_paths[path].place) |
| } |
| |
| fn on_all_children_bits<'tcx, F>( |
| tcx: TyCtxt<'tcx>, |
| body: &Body<'tcx>, |
| move_data: &MoveData<'tcx>, |
| move_path_index: MovePathIndex, |
| each_child: &mut F, |
| ) where |
| F: FnMut(MovePathIndex), |
| { |
| each_child(move_path_index); |
| |
| if is_terminal_path(tcx, body, move_data, move_path_index) { |
| return |
| } |
| |
| let mut next_child_index = move_data.move_paths[move_path_index].first_child; |
| while let Some(child_index) = next_child_index { |
| on_all_children_bits(tcx, body, move_data, child_index, each_child); |
| next_child_index = move_data.move_paths[child_index].next_sibling; |
| } |
| } |
| on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child); |
| } |
| |
| pub(crate) fn on_all_drop_children_bits<'tcx, F>( |
| tcx: TyCtxt<'tcx>, |
| body: &Body<'tcx>, |
| ctxt: &MoveDataParamEnv<'tcx>, |
| path: MovePathIndex, |
| mut each_child: F, |
| ) where |
| F: FnMut(MovePathIndex), |
| { |
| on_all_children_bits(tcx, body, &ctxt.move_data, path, |child| { |
| let place = &ctxt.move_data.move_paths[path].place; |
| let ty = place.ty(body, tcx).ty; |
| debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty); |
| |
| let erased_ty = tcx.erase_regions(&ty); |
| if erased_ty.needs_drop(tcx, ctxt.param_env) { |
| each_child(child); |
| } else { |
| debug!("on_all_drop_children_bits - skipping") |
| } |
| }) |
| } |
| |
| pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>( |
| tcx: TyCtxt<'tcx>, |
| body: &Body<'tcx>, |
| ctxt: &MoveDataParamEnv<'tcx>, |
| mut callback: F, |
| ) where |
| F: FnMut(MovePathIndex, DropFlagState), |
| { |
| let move_data = &ctxt.move_data; |
| for arg in body.args_iter() { |
| let place = mir::Place::from(arg); |
| let lookup_result = move_data.rev_lookup.find(place.as_ref()); |
| on_lookup_result_bits(tcx, body, move_data, |
| lookup_result, |
| |mpi| callback(mpi, DropFlagState::Present)); |
| } |
| } |
| |
| pub(crate) fn drop_flag_effects_for_location<'tcx, F>( |
| tcx: TyCtxt<'tcx>, |
| body: &Body<'tcx>, |
| ctxt: &MoveDataParamEnv<'tcx>, |
| loc: Location, |
| mut callback: F, |
| ) where |
| F: FnMut(MovePathIndex, DropFlagState), |
| { |
| let move_data = &ctxt.move_data; |
| debug!("drop_flag_effects_for_location({:?})", loc); |
| |
| // first, move out of the RHS |
| for mi in &move_data.loc_map[loc] { |
| let path = mi.move_path_index(move_data); |
| debug!("moving out of path {:?}", move_data.move_paths[path]); |
| |
| on_all_children_bits(tcx, body, move_data, |
| path, |
| |mpi| callback(mpi, DropFlagState::Absent)) |
| } |
| |
| debug!("drop_flag_effects: assignment for location({:?})", loc); |
| |
| for_location_inits( |
| tcx, |
| body, |
| move_data, |
| loc, |
| |mpi| callback(mpi, DropFlagState::Present) |
| ); |
| } |
| |
| pub(crate) fn for_location_inits<'tcx, F>( |
| tcx: TyCtxt<'tcx>, |
| body: &Body<'tcx>, |
| move_data: &MoveData<'tcx>, |
| loc: Location, |
| mut callback: F, |
| ) where |
| F: FnMut(MovePathIndex), |
| { |
| for ii in &move_data.init_loc_map[loc] { |
| let init = move_data.inits[*ii]; |
| match init.kind { |
| InitKind::Deep => { |
| let path = init.path; |
| |
| on_all_children_bits(tcx, body, move_data, |
| path, |
| &mut callback) |
| }, |
| InitKind::Shallow => { |
| let mpi = init.path; |
| callback(mpi); |
| } |
| InitKind::NonPanicPathOnly => (), |
| } |
| } |
| } |