]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/dataflow/drop_flag_effects.rs
Make move_path_children_matching closure take a PlaceElem instead of a slice
[rust.git] / src / librustc_mir / dataflow / drop_flag_effects.rs
1 use rustc::mir::{self, Body, Location};
2 use rustc::ty::{self, TyCtxt};
3 use crate::util::elaborate_drops::DropFlagState;
4
5 use super::{MoveDataParamEnv};
6 use super::indexes::MovePathIndex;
7 use super::move_paths::{MoveData, LookupResult, InitKind};
8
9 pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>,
10                                         path: MovePathIndex,
11                                         mut cond: F)
12                                         -> Option<MovePathIndex>
13     where F: FnMut(&mir::PlaceElem<'tcx>) -> bool
14 {
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() {
19             if cond(elem) {
20                 return Some(child_index)
21             }
22         }
23         next_child = move_path_children.next_sibling;
24     }
25
26     None
27 }
28
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`.
32 ///
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.
37 ///
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.
41 ///
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.
45 //
46 // FIXME: we have to do something for moving slice patterns.
47 fn place_contents_drop_state_cannot_differ<'tcx>(
48     tcx: TyCtxt<'tcx>,
49     body: &Body<'tcx>,
50     place: &mir::Place<'tcx>,
51 ) -> bool {
52     let ty = place.ty(body, tcx).ty;
53     match ty.sty {
54         ty::Array(..) => {
55             debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
56                    place, ty);
57             false
58         }
59         ty::Slice(..) | ty::Ref(..) | ty::RawPtr(..) => {
60             debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
61                    place, ty);
62             true
63         }
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",
66                    place, ty);
67             true
68         }
69         _ => {
70             false
71         }
72     }
73 }
74
75 pub(crate) fn on_lookup_result_bits<'tcx, F>(
76     tcx: TyCtxt<'tcx>,
77     body: &Body<'tcx>,
78     move_data: &MoveData<'tcx>,
79     lookup_result: LookupResult,
80     each_child: F,
81 ) where
82     F: FnMut(MovePathIndex),
83 {
84     match lookup_result {
85         LookupResult::Parent(..) => {
86             // access to untracked value - do not touch children
87         }
88         LookupResult::Exact(e) => {
89             on_all_children_bits(tcx, body, move_data, e, each_child)
90         }
91     }
92 }
93
94 pub(crate) fn on_all_children_bits<'tcx, F>(
95     tcx: TyCtxt<'tcx>,
96     body: &Body<'tcx>,
97     move_data: &MoveData<'tcx>,
98     move_path_index: MovePathIndex,
99     mut each_child: F,
100 ) where
101     F: FnMut(MovePathIndex),
102 {
103     fn is_terminal_path<'tcx>(
104         tcx: TyCtxt<'tcx>,
105         body: &Body<'tcx>,
106         move_data: &MoveData<'tcx>,
107         path: MovePathIndex,
108     ) -> bool {
109         place_contents_drop_state_cannot_differ(
110             tcx, body, &move_data.move_paths[path].place)
111     }
112
113     fn on_all_children_bits<'tcx, F>(
114         tcx: TyCtxt<'tcx>,
115         body: &Body<'tcx>,
116         move_data: &MoveData<'tcx>,
117         move_path_index: MovePathIndex,
118         each_child: &mut F,
119     ) where
120         F: FnMut(MovePathIndex),
121     {
122         each_child(move_path_index);
123
124         if is_terminal_path(tcx, body, move_data, move_path_index) {
125             return
126         }
127
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;
132         }
133     }
134     on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child);
135 }
136
137 pub(crate) fn on_all_drop_children_bits<'tcx, F>(
138     tcx: TyCtxt<'tcx>,
139     body: &Body<'tcx>,
140     ctxt: &MoveDataParamEnv<'tcx>,
141     path: MovePathIndex,
142     mut each_child: F,
143 ) where
144     F: FnMut(MovePathIndex),
145 {
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);
150
151         let gcx = tcx.global_tcx();
152         let erased_ty = tcx.erase_regions(&ty);
153         if erased_ty.needs_drop(gcx, ctxt.param_env) {
154             each_child(child);
155         } else {
156             debug!("on_all_drop_children_bits - skipping")
157         }
158     })
159 }
160
161 pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>(
162     tcx: TyCtxt<'tcx>,
163     body: &Body<'tcx>,
164     ctxt: &MoveDataParamEnv<'tcx>,
165     mut callback: F,
166 ) where
167     F: FnMut(MovePathIndex, DropFlagState),
168 {
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,
174                               lookup_result,
175                               |mpi| callback(mpi, DropFlagState::Present));
176     }
177 }
178
179 pub(crate) fn drop_flag_effects_for_location<'tcx, F>(
180     tcx: TyCtxt<'tcx>,
181     body: &Body<'tcx>,
182     ctxt: &MoveDataParamEnv<'tcx>,
183     loc: Location,
184     mut callback: F,
185 ) where
186     F: FnMut(MovePathIndex, DropFlagState),
187 {
188     let move_data = &ctxt.move_data;
189     debug!("drop_flag_effects_for_location({:?})", loc);
190
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]);
195
196         on_all_children_bits(tcx, body, move_data,
197                              path,
198                              |mpi| callback(mpi, DropFlagState::Absent))
199     }
200
201     debug!("drop_flag_effects: assignment for location({:?})", loc);
202
203     for_location_inits(
204         tcx,
205         body,
206         move_data,
207         loc,
208         |mpi| callback(mpi, DropFlagState::Present)
209     );
210 }
211
212 pub(crate) fn for_location_inits<'tcx, F>(
213     tcx: TyCtxt<'tcx>,
214     body: &Body<'tcx>,
215     move_data: &MoveData<'tcx>,
216     loc: Location,
217     mut callback: F,
218 ) where
219     F: FnMut(MovePathIndex),
220 {
221     for ii in &move_data.init_loc_map[loc] {
222         let init = move_data.inits[*ii];
223         match init.kind {
224             InitKind::Deep => {
225                 let path = init.path;
226
227                 on_all_children_bits(tcx, body, move_data,
228                                     path,
229                                     &mut callback)
230             },
231             InitKind::Shallow => {
232                 let mpi = init.path;
233                 callback(mpi);
234             }
235             InitKind::NonPanicPathOnly => (),
236         }
237     }
238 }