]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | use crate::util::elaborate_drops::DropFlagState; |
ba9703b0 XL |
2 | use rustc_middle::mir::{self, Body, Location}; |
3 | use rustc_middle::ty::{self, TyCtxt}; | |
f035d41b | 4 | use rustc_target::abi::VariantIdx; |
54a0048b | 5 | |
041b39d2 | 6 | use super::indexes::MovePathIndex; |
dfeec247 XL |
7 | use super::move_paths::{InitKind, LookupResult, MoveData}; |
8 | use super::MoveDataParamEnv; | |
041b39d2 | 9 | |
dfeec247 XL |
10 | pub fn move_path_children_matching<'tcx, F>( |
11 | move_data: &MoveData<'tcx>, | |
12 | path: MovePathIndex, | |
13 | mut cond: F, | |
14 | ) -> Option<MovePathIndex> | |
15 | where | |
f9f354fc | 16 | F: FnMut(mir::PlaceElem<'tcx>) -> bool, |
3157f602 | 17 | { |
9e0c209e | 18 | let mut next_child = move_data.move_paths[path].first_child; |
3157f602 | 19 | while let Some(child_index) = next_child { |
e1599b0c | 20 | let move_path_children = &move_data.move_paths[child_index]; |
f9f354fc | 21 | if let Some(&elem) = move_path_children.place.projection.last() { |
e1599b0c | 22 | if cond(elem) { |
dfeec247 | 23 | return Some(child_index); |
3157f602 | 24 | } |
3157f602 | 25 | } |
e1599b0c | 26 | next_child = move_path_children.next_sibling; |
3157f602 XL |
27 | } |
28 | ||
29 | None | |
30 | } | |
31 | ||
32 | /// When enumerating the child fragments of a path, don't recurse into | |
33 | /// paths (1.) past arrays, slices, and pointers, nor (2.) into a type | |
34 | /// that implements `Drop`. | |
35 | /// | |
ff7c6d11 | 36 | /// Places behind references or arrays are not tracked by elaboration |
3157f602 XL |
37 | /// and are always assumed to be initialized when accessible. As |
38 | /// references and indexes can be reseated, trying to track them can | |
39 | /// only lead to trouble. | |
40 | /// | |
ff7c6d11 | 41 | /// Places behind ADT's with a Drop impl are not tracked by |
3157f602 XL |
42 | /// elaboration since they can never have a drop-flag state that |
43 | /// differs from that of the parent with the Drop impl. | |
44 | /// | |
45 | /// In both cases, the contents can only be accessed if and only if | |
46 | /// their parents are initialized. This implies for example that there | |
47 | /// is no need to maintain separate drop flags to track such state. | |
9fa01778 XL |
48 | // |
49 | // FIXME: we have to do something for moving slice patterns. | |
dc9dc135 XL |
50 | fn place_contents_drop_state_cannot_differ<'tcx>( |
51 | tcx: TyCtxt<'tcx>, | |
52 | body: &Body<'tcx>, | |
ba9703b0 | 53 | place: mir::Place<'tcx>, |
dc9dc135 XL |
54 | ) -> bool { |
55 | let ty = place.ty(body, tcx).ty; | |
e74abb32 | 56 | match ty.kind { |
b7449926 | 57 | ty::Array(..) => { |
dfeec247 XL |
58 | debug!( |
59 | "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false", | |
60 | place, ty | |
61 | ); | |
ff7c6d11 XL |
62 | false |
63 | } | |
b7449926 | 64 | ty::Slice(..) | ty::Ref(..) | ty::RawPtr(..) => { |
dfeec247 XL |
65 | debug!( |
66 | "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true", | |
67 | place, ty | |
68 | ); | |
3157f602 XL |
69 | true |
70 | } | |
b7449926 | 71 | ty::Adt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => { |
dfeec247 XL |
72 | debug!( |
73 | "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} Drop => true", | |
74 | place, ty | |
75 | ); | |
3157f602 XL |
76 | true |
77 | } | |
dfeec247 | 78 | _ => false, |
3157f602 XL |
79 | } |
80 | } | |
81 | ||
dc9dc135 XL |
82 | pub(crate) fn on_lookup_result_bits<'tcx, F>( |
83 | tcx: TyCtxt<'tcx>, | |
84 | body: &Body<'tcx>, | |
9e0c209e SL |
85 | move_data: &MoveData<'tcx>, |
86 | lookup_result: LookupResult, | |
dc9dc135 XL |
87 | each_child: F, |
88 | ) where | |
89 | F: FnMut(MovePathIndex), | |
9e0c209e SL |
90 | { |
91 | match lookup_result { | |
92 | LookupResult::Parent(..) => { | |
93 | // access to untracked value - do not touch children | |
94 | } | |
dfeec247 | 95 | LookupResult::Exact(e) => on_all_children_bits(tcx, body, move_data, e, each_child), |
9e0c209e SL |
96 | } |
97 | } | |
98 | ||
dc9dc135 XL |
99 | pub(crate) fn on_all_children_bits<'tcx, F>( |
100 | tcx: TyCtxt<'tcx>, | |
101 | body: &Body<'tcx>, | |
3157f602 XL |
102 | move_data: &MoveData<'tcx>, |
103 | move_path_index: MovePathIndex, | |
dc9dc135 XL |
104 | mut each_child: F, |
105 | ) where | |
106 | F: FnMut(MovePathIndex), | |
3157f602 | 107 | { |
dc9dc135 XL |
108 | fn is_terminal_path<'tcx>( |
109 | tcx: TyCtxt<'tcx>, | |
110 | body: &Body<'tcx>, | |
3157f602 | 111 | move_data: &MoveData<'tcx>, |
dc9dc135 XL |
112 | path: MovePathIndex, |
113 | ) -> bool { | |
ba9703b0 | 114 | place_contents_drop_state_cannot_differ(tcx, body, move_data.move_paths[path].place) |
3157f602 XL |
115 | } |
116 | ||
dc9dc135 XL |
117 | fn on_all_children_bits<'tcx, F>( |
118 | tcx: TyCtxt<'tcx>, | |
119 | body: &Body<'tcx>, | |
3157f602 XL |
120 | move_data: &MoveData<'tcx>, |
121 | move_path_index: MovePathIndex, | |
dc9dc135 XL |
122 | each_child: &mut F, |
123 | ) where | |
124 | F: FnMut(MovePathIndex), | |
3157f602 XL |
125 | { |
126 | each_child(move_path_index); | |
127 | ||
dc9dc135 | 128 | if is_terminal_path(tcx, body, move_data, move_path_index) { |
dfeec247 | 129 | return; |
3157f602 XL |
130 | } |
131 | ||
132 | let mut next_child_index = move_data.move_paths[move_path_index].first_child; | |
133 | while let Some(child_index) = next_child_index { | |
dc9dc135 | 134 | on_all_children_bits(tcx, body, move_data, child_index, each_child); |
3157f602 XL |
135 | next_child_index = move_data.move_paths[child_index].next_sibling; |
136 | } | |
137 | } | |
dc9dc135 | 138 | on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child); |
3157f602 XL |
139 | } |
140 | ||
dc9dc135 XL |
141 | pub(crate) fn on_all_drop_children_bits<'tcx, F>( |
142 | tcx: TyCtxt<'tcx>, | |
143 | body: &Body<'tcx>, | |
144 | ctxt: &MoveDataParamEnv<'tcx>, | |
cc61c64b | 145 | path: MovePathIndex, |
dc9dc135 XL |
146 | mut each_child: F, |
147 | ) where | |
148 | F: FnMut(MovePathIndex), | |
cc61c64b | 149 | { |
dc9dc135 | 150 | on_all_children_bits(tcx, body, &ctxt.move_data, path, |child| { |
ff7c6d11 | 151 | let place = &ctxt.move_data.move_paths[path].place; |
dc9dc135 | 152 | let ty = place.ty(body, tcx).ty; |
ff7c6d11 | 153 | debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty); |
cc61c64b | 154 | |
dc9dc135 | 155 | let erased_ty = tcx.erase_regions(&ty); |
e74abb32 | 156 | if erased_ty.needs_drop(tcx, ctxt.param_env) { |
cc61c64b XL |
157 | each_child(child); |
158 | } else { | |
159 | debug!("on_all_drop_children_bits - skipping") | |
160 | } | |
161 | }) | |
162 | } | |
163 | ||
dc9dc135 XL |
164 | pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>( |
165 | tcx: TyCtxt<'tcx>, | |
166 | body: &Body<'tcx>, | |
167 | ctxt: &MoveDataParamEnv<'tcx>, | |
168 | mut callback: F, | |
169 | ) where | |
170 | F: FnMut(MovePathIndex, DropFlagState), | |
3157f602 XL |
171 | { |
172 | let move_data = &ctxt.move_data; | |
dc9dc135 XL |
173 | for arg in body.args_iter() { |
174 | let place = mir::Place::from(arg); | |
416331ca | 175 | let lookup_result = move_data.rev_lookup.find(place.as_ref()); |
dfeec247 XL |
176 | on_lookup_result_bits(tcx, body, move_data, lookup_result, |mpi| { |
177 | callback(mpi, DropFlagState::Present) | |
178 | }); | |
3157f602 XL |
179 | } |
180 | } | |
181 | ||
dc9dc135 XL |
182 | pub(crate) fn drop_flag_effects_for_location<'tcx, F>( |
183 | tcx: TyCtxt<'tcx>, | |
184 | body: &Body<'tcx>, | |
185 | ctxt: &MoveDataParamEnv<'tcx>, | |
3157f602 | 186 | loc: Location, |
dc9dc135 XL |
187 | mut callback: F, |
188 | ) where | |
189 | F: FnMut(MovePathIndex, DropFlagState), | |
3157f602 XL |
190 | { |
191 | let move_data = &ctxt.move_data; | |
3157f602 XL |
192 | debug!("drop_flag_effects_for_location({:?})", loc); |
193 | ||
194 | // first, move out of the RHS | |
195 | for mi in &move_data.loc_map[loc] { | |
196 | let path = mi.move_path_index(move_data); | |
197 | debug!("moving out of path {:?}", move_data.move_paths[path]); | |
198 | ||
dfeec247 | 199 | on_all_children_bits(tcx, body, move_data, path, |mpi| callback(mpi, DropFlagState::Absent)) |
3157f602 XL |
200 | } |
201 | ||
ff7c6d11 XL |
202 | debug!("drop_flag_effects: assignment for location({:?})", loc); |
203 | ||
dfeec247 | 204 | for_location_inits(tcx, body, move_data, loc, |mpi| callback(mpi, DropFlagState::Present)); |
ff7c6d11 XL |
205 | } |
206 | ||
dc9dc135 XL |
207 | pub(crate) fn for_location_inits<'tcx, F>( |
208 | tcx: TyCtxt<'tcx>, | |
209 | body: &Body<'tcx>, | |
ff7c6d11 XL |
210 | move_data: &MoveData<'tcx>, |
211 | loc: Location, | |
dc9dc135 XL |
212 | mut callback: F, |
213 | ) where | |
214 | F: FnMut(MovePathIndex), | |
ff7c6d11 XL |
215 | { |
216 | for ii in &move_data.init_loc_map[loc] { | |
217 | let init = move_data.inits[*ii]; | |
218 | match init.kind { | |
219 | InitKind::Deep => { | |
220 | let path = init.path; | |
221 | ||
dfeec247 XL |
222 | on_all_children_bits(tcx, body, move_data, path, &mut callback) |
223 | } | |
ff7c6d11 XL |
224 | InitKind::Shallow => { |
225 | let mpi = init.path; | |
226 | callback(mpi); | |
3157f602 | 227 | } |
ff7c6d11 | 228 | InitKind::NonPanicPathOnly => (), |
3157f602 XL |
229 | } |
230 | } | |
231 | } | |
f035d41b XL |
232 | |
233 | /// Calls `handle_inactive_variant` for each descendant move path of `enum_place` that contains a | |
234 | /// `Downcast` to a variant besides the `active_variant`. | |
235 | /// | |
236 | /// NOTE: If there are no move paths corresponding to an inactive variant, | |
237 | /// `handle_inactive_variant` will not be called for that variant. | |
238 | pub(crate) fn on_all_inactive_variants<'tcx>( | |
239 | tcx: TyCtxt<'tcx>, | |
240 | body: &mir::Body<'tcx>, | |
241 | move_data: &MoveData<'tcx>, | |
242 | enum_place: mir::Place<'tcx>, | |
243 | active_variant: VariantIdx, | |
244 | mut handle_inactive_variant: impl FnMut(MovePathIndex), | |
245 | ) { | |
246 | let enum_mpi = match move_data.rev_lookup.find(enum_place.as_ref()) { | |
247 | LookupResult::Exact(mpi) => mpi, | |
248 | LookupResult::Parent(_) => return, | |
249 | }; | |
250 | ||
251 | let enum_path = &move_data.move_paths[enum_mpi]; | |
252 | for (variant_mpi, variant_path) in enum_path.children(&move_data.move_paths) { | |
253 | // Because of the way we build the `MoveData` tree, each child should have exactly one more | |
254 | // projection than `enum_place`. This additional projection must be a downcast since the | |
255 | // base is an enum. | |
256 | let (downcast, base_proj) = variant_path.place.projection.split_last().unwrap(); | |
257 | assert_eq!(enum_place.projection.len(), base_proj.len()); | |
258 | ||
259 | let variant_idx = match *downcast { | |
260 | mir::ProjectionElem::Downcast(_, idx) => idx, | |
261 | _ => unreachable!(), | |
262 | }; | |
263 | ||
264 | if variant_idx != active_variant { | |
265 | on_all_children_bits(tcx, body, move_data, variant_mpi, |mpi| { | |
266 | handle_inactive_variant(mpi) | |
267 | }); | |
268 | } | |
269 | } | |
270 | } |