1 // Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use rustc::mir::{self, Mir, Location};
12 use rustc::ty::{self, TyCtxt};
13 use util::elaborate_drops::DropFlagState;
15 use super::{MoveDataParamEnv};
16 use super::indexes::MovePathIndex;
17 use super::move_paths::{MoveData, LookupResult, InitKind};
19 pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>,
22 -> Option<MovePathIndex>
23 where F: FnMut(&mir::PlaceProjection<'tcx>) -> bool
25 let mut next_child = move_data.move_paths[path].first_child;
26 while let Some(child_index) = next_child {
27 match move_data.move_paths[child_index].place {
28 mir::Place::Projection(ref proj) => {
30 return Some(child_index)
35 next_child = move_data.move_paths[child_index].next_sibling;
41 /// When enumerating the child fragments of a path, don't recurse into
42 /// paths (1.) past arrays, slices, and pointers, nor (2.) into a type
43 /// that implements `Drop`.
45 /// Places behind references or arrays are not tracked by elaboration
46 /// and are always assumed to be initialized when accessible. As
47 /// references and indexes can be reseated, trying to track them can
48 /// only lead to trouble.
50 /// Places behind ADT's with a Drop impl are not tracked by
51 /// elaboration since they can never have a drop-flag state that
52 /// differs from that of the parent with the Drop impl.
54 /// In both cases, the contents can only be accessed if and only if
55 /// their parents are initialized. This implies for example that there
56 /// is no need to maintain separate drop flags to track such state.
58 /// FIXME: we have to do something for moving slice patterns.
59 fn place_contents_drop_state_cannot_differ<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
61 place: &mir::Place<'tcx>) -> bool {
62 let ty = place.ty(mir, tcx).to_ty(tcx);
65 debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
69 ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
70 debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
74 ty::TyAdt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => {
75 debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} Drop => true",
85 pub(crate) fn on_lookup_result_bits<'a, 'gcx, 'tcx, F>(
86 tcx: TyCtxt<'a, 'gcx, 'tcx>,
88 move_data: &MoveData<'tcx>,
89 lookup_result: LookupResult,
91 where F: FnMut(MovePathIndex)
94 LookupResult::Parent(..) => {
95 // access to untracked value - do not touch children
97 LookupResult::Exact(e) => {
98 on_all_children_bits(tcx, mir, move_data, e, each_child)
103 pub(crate) fn on_all_children_bits<'a, 'gcx, 'tcx, F>(
104 tcx: TyCtxt<'a, 'gcx, 'tcx>,
106 move_data: &MoveData<'tcx>,
107 move_path_index: MovePathIndex,
109 where F: FnMut(MovePathIndex)
111 fn is_terminal_path<'a, 'gcx, 'tcx>(
112 tcx: TyCtxt<'a, 'gcx, 'tcx>,
114 move_data: &MoveData<'tcx>,
115 path: MovePathIndex) -> bool
117 place_contents_drop_state_cannot_differ(
118 tcx, mir, &move_data.move_paths[path].place)
121 fn on_all_children_bits<'a, 'gcx, 'tcx, F>(
122 tcx: TyCtxt<'a, 'gcx, 'tcx>,
124 move_data: &MoveData<'tcx>,
125 move_path_index: MovePathIndex,
127 where F: FnMut(MovePathIndex)
129 each_child(move_path_index);
131 if is_terminal_path(tcx, mir, move_data, move_path_index) {
135 let mut next_child_index = move_data.move_paths[move_path_index].first_child;
136 while let Some(child_index) = next_child_index {
137 on_all_children_bits(tcx, mir, move_data, child_index, each_child);
138 next_child_index = move_data.move_paths[child_index].next_sibling;
141 on_all_children_bits(tcx, mir, move_data, move_path_index, &mut each_child);
144 pub(crate) fn on_all_drop_children_bits<'a, 'gcx, 'tcx, F>(
145 tcx: TyCtxt<'a, 'gcx, 'tcx>,
147 ctxt: &MoveDataParamEnv<'gcx, 'tcx>,
150 where F: FnMut(MovePathIndex)
152 on_all_children_bits(tcx, mir, &ctxt.move_data, path, |child| {
153 let place = &ctxt.move_data.move_paths[path].place;
154 let ty = place.ty(mir, tcx).to_ty(tcx);
155 debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty);
157 let gcx = tcx.global_tcx();
158 let erased_ty = gcx.lift(&tcx.erase_regions(&ty)).unwrap();
159 if erased_ty.needs_drop(gcx, ctxt.param_env) {
162 debug!("on_all_drop_children_bits - skipping")
167 pub(crate) fn drop_flag_effects_for_function_entry<'a, 'gcx, 'tcx, F>(
168 tcx: TyCtxt<'a, 'gcx, 'tcx>,
170 ctxt: &MoveDataParamEnv<'gcx, 'tcx>,
172 where F: FnMut(MovePathIndex, DropFlagState)
174 let move_data = &ctxt.move_data;
175 for arg in mir.args_iter() {
176 let place = mir::Place::Local(arg);
177 let lookup_result = move_data.rev_lookup.find(&place);
178 on_lookup_result_bits(tcx, mir, move_data,
180 |mpi| callback(mpi, DropFlagState::Present));
184 pub(crate) fn drop_flag_effects_for_location<'a, 'gcx, 'tcx, F>(
185 tcx: TyCtxt<'a, 'gcx, 'tcx>,
187 ctxt: &MoveDataParamEnv<'gcx, 'tcx>,
190 where F: FnMut(MovePathIndex, DropFlagState)
192 let move_data = &ctxt.move_data;
193 debug!("drop_flag_effects_for_location({:?})", loc);
195 // first, move out of the RHS
196 for mi in &move_data.loc_map[loc] {
197 let path = mi.move_path_index(move_data);
198 debug!("moving out of path {:?}", move_data.move_paths[path]);
200 on_all_children_bits(tcx, mir, move_data,
202 |mpi| callback(mpi, DropFlagState::Absent))
205 debug!("drop_flag_effects: assignment for location({:?})", loc);
212 |mpi| callback(mpi, DropFlagState::Present)
216 pub(crate) fn for_location_inits<'a, 'gcx, 'tcx, F>(
217 tcx: TyCtxt<'a, 'gcx, 'tcx>,
219 move_data: &MoveData<'tcx>,
222 where F: FnMut(MovePathIndex)
224 for ii in &move_data.init_loc_map[loc] {
225 let init = move_data.inits[*ii];
228 let path = init.path;
230 on_all_children_bits(tcx, mir, move_data,
234 InitKind::Shallow => {
238 InitKind::NonPanicPathOnly => (),