]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/dataflow/drop_flag_effects.rs
New upstream version 1.42.0+dfsg1
[rustc.git] / src / librustc_mir / dataflow / drop_flag_effects.rs
1 use crate::util::elaborate_drops::DropFlagState;
2 use rustc::mir::{self, Body, Location};
3 use rustc::ty::{self, TyCtxt};
4
5 use super::indexes::MovePathIndex;
6 use super::move_paths::{InitKind, LookupResult, MoveData};
7 use super::MoveDataParamEnv;
8
9 pub fn move_path_children_matching<'tcx, F>(
10 move_data: &MoveData<'tcx>,
11 path: MovePathIndex,
12 mut cond: F,
13 ) -> Option<MovePathIndex>
14 where
15 F: FnMut(&mir::PlaceElem<'tcx>) -> bool,
16 {
17 let mut next_child = move_data.move_paths[path].first_child;
18 while let Some(child_index) = next_child {
19 let move_path_children = &move_data.move_paths[child_index];
20 if let Some(elem) = move_path_children.place.projection.last() {
21 if cond(elem) {
22 return Some(child_index);
23 }
24 }
25 next_child = move_path_children.next_sibling;
26 }
27
28 None
29 }
30
31 /// When enumerating the child fragments of a path, don't recurse into
32 /// paths (1.) past arrays, slices, and pointers, nor (2.) into a type
33 /// that implements `Drop`.
34 ///
35 /// Places behind references or arrays are not tracked by elaboration
36 /// and are always assumed to be initialized when accessible. As
37 /// references and indexes can be reseated, trying to track them can
38 /// only lead to trouble.
39 ///
40 /// Places behind ADT's with a Drop impl are not tracked by
41 /// elaboration since they can never have a drop-flag state that
42 /// differs from that of the parent with the Drop impl.
43 ///
44 /// In both cases, the contents can only be accessed if and only if
45 /// their parents are initialized. This implies for example that there
46 /// is no need to maintain separate drop flags to track such state.
47 //
48 // FIXME: we have to do something for moving slice patterns.
49 fn place_contents_drop_state_cannot_differ<'tcx>(
50 tcx: TyCtxt<'tcx>,
51 body: &Body<'tcx>,
52 place: &mir::Place<'tcx>,
53 ) -> bool {
54 let ty = place.ty(body, tcx).ty;
55 match ty.kind {
56 ty::Array(..) => {
57 debug!(
58 "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
59 place, ty
60 );
61 false
62 }
63 ty::Slice(..) | ty::Ref(..) | ty::RawPtr(..) => {
64 debug!(
65 "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
66 place, ty
67 );
68 true
69 }
70 ty::Adt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => {
71 debug!(
72 "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} Drop => true",
73 place, ty
74 );
75 true
76 }
77 _ => false,
78 }
79 }
80
81 pub(crate) fn on_lookup_result_bits<'tcx, F>(
82 tcx: TyCtxt<'tcx>,
83 body: &Body<'tcx>,
84 move_data: &MoveData<'tcx>,
85 lookup_result: LookupResult,
86 each_child: F,
87 ) where
88 F: FnMut(MovePathIndex),
89 {
90 match lookup_result {
91 LookupResult::Parent(..) => {
92 // access to untracked value - do not touch children
93 }
94 LookupResult::Exact(e) => on_all_children_bits(tcx, body, move_data, e, each_child),
95 }
96 }
97
98 pub(crate) fn on_all_children_bits<'tcx, F>(
99 tcx: TyCtxt<'tcx>,
100 body: &Body<'tcx>,
101 move_data: &MoveData<'tcx>,
102 move_path_index: MovePathIndex,
103 mut each_child: F,
104 ) where
105 F: FnMut(MovePathIndex),
106 {
107 fn is_terminal_path<'tcx>(
108 tcx: TyCtxt<'tcx>,
109 body: &Body<'tcx>,
110 move_data: &MoveData<'tcx>,
111 path: MovePathIndex,
112 ) -> bool {
113 place_contents_drop_state_cannot_differ(tcx, body, &move_data.move_paths[path].place)
114 }
115
116 fn on_all_children_bits<'tcx, F>(
117 tcx: TyCtxt<'tcx>,
118 body: &Body<'tcx>,
119 move_data: &MoveData<'tcx>,
120 move_path_index: MovePathIndex,
121 each_child: &mut F,
122 ) where
123 F: FnMut(MovePathIndex),
124 {
125 each_child(move_path_index);
126
127 if is_terminal_path(tcx, body, move_data, move_path_index) {
128 return;
129 }
130
131 let mut next_child_index = move_data.move_paths[move_path_index].first_child;
132 while let Some(child_index) = next_child_index {
133 on_all_children_bits(tcx, body, move_data, child_index, each_child);
134 next_child_index = move_data.move_paths[child_index].next_sibling;
135 }
136 }
137 on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child);
138 }
139
140 pub(crate) fn on_all_drop_children_bits<'tcx, F>(
141 tcx: TyCtxt<'tcx>,
142 body: &Body<'tcx>,
143 ctxt: &MoveDataParamEnv<'tcx>,
144 path: MovePathIndex,
145 mut each_child: F,
146 ) where
147 F: FnMut(MovePathIndex),
148 {
149 on_all_children_bits(tcx, body, &ctxt.move_data, path, |child| {
150 let place = &ctxt.move_data.move_paths[path].place;
151 let ty = place.ty(body, tcx).ty;
152 debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty);
153
154 let erased_ty = tcx.erase_regions(&ty);
155 if erased_ty.needs_drop(tcx, ctxt.param_env) {
156 each_child(child);
157 } else {
158 debug!("on_all_drop_children_bits - skipping")
159 }
160 })
161 }
162
163 pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>(
164 tcx: TyCtxt<'tcx>,
165 body: &Body<'tcx>,
166 ctxt: &MoveDataParamEnv<'tcx>,
167 mut callback: F,
168 ) where
169 F: FnMut(MovePathIndex, DropFlagState),
170 {
171 let move_data = &ctxt.move_data;
172 for arg in body.args_iter() {
173 let place = mir::Place::from(arg);
174 let lookup_result = move_data.rev_lookup.find(place.as_ref());
175 on_lookup_result_bits(tcx, body, move_data, lookup_result, |mpi| {
176 callback(mpi, DropFlagState::Present)
177 });
178 }
179 }
180
181 pub(crate) fn drop_flag_effects_for_location<'tcx, F>(
182 tcx: TyCtxt<'tcx>,
183 body: &Body<'tcx>,
184 ctxt: &MoveDataParamEnv<'tcx>,
185 loc: Location,
186 mut callback: F,
187 ) where
188 F: FnMut(MovePathIndex, DropFlagState),
189 {
190 let move_data = &ctxt.move_data;
191 debug!("drop_flag_effects_for_location({:?})", loc);
192
193 // first, move out of the RHS
194 for mi in &move_data.loc_map[loc] {
195 let path = mi.move_path_index(move_data);
196 debug!("moving out of path {:?}", move_data.move_paths[path]);
197
198 on_all_children_bits(tcx, body, move_data, path, |mpi| callback(mpi, DropFlagState::Absent))
199 }
200
201 debug!("drop_flag_effects: assignment for location({:?})", loc);
202
203 for_location_inits(tcx, body, move_data, loc, |mpi| callback(mpi, DropFlagState::Present));
204 }
205
206 pub(crate) fn for_location_inits<'tcx, F>(
207 tcx: TyCtxt<'tcx>,
208 body: &Body<'tcx>,
209 move_data: &MoveData<'tcx>,
210 loc: Location,
211 mut callback: F,
212 ) where
213 F: FnMut(MovePathIndex),
214 {
215 for ii in &move_data.init_loc_map[loc] {
216 let init = move_data.inits[*ii];
217 match init.kind {
218 InitKind::Deep => {
219 let path = init.path;
220
221 on_all_children_bits(tcx, body, move_data, path, &mut callback)
222 }
223 InitKind::Shallow => {
224 let mpi = init.path;
225 callback(mpi);
226 }
227 InitKind::NonPanicPathOnly => (),
228 }
229 }
230 }