]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/dataflow/drop_flag_effects.rs
New upstream version 1.47.0+dfsg1
[rustc.git] / src / librustc_mir / dataflow / drop_flag_effects.rs
CommitLineData
dfeec247 1use crate::util::elaborate_drops::DropFlagState;
ba9703b0
XL
2use rustc_middle::mir::{self, Body, Location};
3use rustc_middle::ty::{self, TyCtxt};
f035d41b 4use rustc_target::abi::VariantIdx;
54a0048b 5
041b39d2 6use super::indexes::MovePathIndex;
dfeec247
XL
7use super::move_paths::{InitKind, LookupResult, MoveData};
8use super::MoveDataParamEnv;
041b39d2 9
dfeec247
XL
10pub fn move_path_children_matching<'tcx, F>(
11 move_data: &MoveData<'tcx>,
12 path: MovePathIndex,
13 mut cond: F,
14) -> Option<MovePathIndex>
15where
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
50fn 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
82pub(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
99pub(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
141pub(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
164pub(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
182pub(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
207pub(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.
238pub(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}