]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/dataflow/drop_flag_effects.rs
Changes the type `mir::Mir` into `mir::Body`
[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::Projection<'tcx>) -> bool
14 {
15     let mut next_child = move_data.move_paths[path].first_child;
16     while let Some(child_index) = next_child {
17         match move_data.move_paths[child_index].place {
18             mir::Place::Projection(ref proj) => {
19                 if cond(proj) {
20                     return Some(child_index)
21                 }
22             }
23             _ => {}
24         }
25         next_child = move_data.move_paths[child_index].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<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
50                                                             mir: &Body<'tcx>,
51                                                             place: &mir::Place<'tcx>) -> bool {
52     let ty = place.ty(mir, 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<'a, 'gcx, 'tcx, F>(
76     tcx: TyCtxt<'a, 'gcx, 'tcx>,
77     mir: &Body<'tcx>,
78     move_data: &MoveData<'tcx>,
79     lookup_result: LookupResult,
80     each_child: F)
81     where F: FnMut(MovePathIndex)
82 {
83     match lookup_result {
84         LookupResult::Parent(..) => {
85             // access to untracked value - do not touch children
86         }
87         LookupResult::Exact(e) => {
88             on_all_children_bits(tcx, mir, move_data, e, each_child)
89         }
90     }
91 }
92
93 pub(crate) fn on_all_children_bits<'a, 'gcx, 'tcx, F>(
94     tcx: TyCtxt<'a, 'gcx, 'tcx>,
95     mir: &Body<'tcx>,
96     move_data: &MoveData<'tcx>,
97     move_path_index: MovePathIndex,
98     mut each_child: F)
99     where F: FnMut(MovePathIndex)
100 {
101     fn is_terminal_path<'a, 'gcx, 'tcx>(
102         tcx: TyCtxt<'a, 'gcx, 'tcx>,
103         mir: &Body<'tcx>,
104         move_data: &MoveData<'tcx>,
105         path: MovePathIndex) -> bool
106     {
107         place_contents_drop_state_cannot_differ(
108             tcx, mir, &move_data.move_paths[path].place)
109     }
110
111     fn on_all_children_bits<'a, 'gcx, 'tcx, F>(
112         tcx: TyCtxt<'a, 'gcx, 'tcx>,
113         mir: &Body<'tcx>,
114         move_data: &MoveData<'tcx>,
115         move_path_index: MovePathIndex,
116         each_child: &mut F)
117         where F: FnMut(MovePathIndex)
118     {
119         each_child(move_path_index);
120
121         if is_terminal_path(tcx, mir, move_data, move_path_index) {
122             return
123         }
124
125         let mut next_child_index = move_data.move_paths[move_path_index].first_child;
126         while let Some(child_index) = next_child_index {
127             on_all_children_bits(tcx, mir, move_data, child_index, each_child);
128             next_child_index = move_data.move_paths[child_index].next_sibling;
129         }
130     }
131     on_all_children_bits(tcx, mir, move_data, move_path_index, &mut each_child);
132 }
133
134 pub(crate) fn on_all_drop_children_bits<'a, 'gcx, 'tcx, F>(
135     tcx: TyCtxt<'a, 'gcx, 'tcx>,
136     mir: &Body<'tcx>,
137     ctxt: &MoveDataParamEnv<'gcx, 'tcx>,
138     path: MovePathIndex,
139     mut each_child: F)
140     where F: FnMut(MovePathIndex)
141 {
142     on_all_children_bits(tcx, mir, &ctxt.move_data, path, |child| {
143         let place = &ctxt.move_data.move_paths[path].place;
144         let ty = place.ty(mir, tcx).ty;
145         debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty);
146
147         let gcx = tcx.global_tcx();
148         let erased_ty = gcx.lift(&tcx.erase_regions(&ty)).unwrap();
149         if erased_ty.needs_drop(gcx, ctxt.param_env) {
150             each_child(child);
151         } else {
152             debug!("on_all_drop_children_bits - skipping")
153         }
154     })
155 }
156
157 pub(crate) fn drop_flag_effects_for_function_entry<'a, 'gcx, 'tcx, F>(
158     tcx: TyCtxt<'a, 'gcx, 'tcx>,
159     mir: &Body<'tcx>,
160     ctxt: &MoveDataParamEnv<'gcx, 'tcx>,
161     mut callback: F)
162     where F: FnMut(MovePathIndex, DropFlagState)
163 {
164     let move_data = &ctxt.move_data;
165     for arg in mir.args_iter() {
166         let place = mir::Place::Base(mir::PlaceBase::Local(arg));
167         let lookup_result = move_data.rev_lookup.find(&place);
168         on_lookup_result_bits(tcx, mir, move_data,
169                               lookup_result,
170                               |mpi| callback(mpi, DropFlagState::Present));
171     }
172 }
173
174 pub(crate) fn drop_flag_effects_for_location<'a, 'gcx, 'tcx, F>(
175     tcx: TyCtxt<'a, 'gcx, 'tcx>,
176     mir: &Body<'tcx>,
177     ctxt: &MoveDataParamEnv<'gcx, 'tcx>,
178     loc: Location,
179     mut callback: F)
180     where F: FnMut(MovePathIndex, DropFlagState)
181 {
182     let move_data = &ctxt.move_data;
183     debug!("drop_flag_effects_for_location({:?})", loc);
184
185     // first, move out of the RHS
186     for mi in &move_data.loc_map[loc] {
187         let path = mi.move_path_index(move_data);
188         debug!("moving out of path {:?}", move_data.move_paths[path]);
189
190         on_all_children_bits(tcx, mir, move_data,
191                              path,
192                              |mpi| callback(mpi, DropFlagState::Absent))
193     }
194
195     debug!("drop_flag_effects: assignment for location({:?})", loc);
196
197     for_location_inits(
198         tcx,
199         mir,
200         move_data,
201         loc,
202         |mpi| callback(mpi, DropFlagState::Present)
203     );
204 }
205
206 pub(crate) fn for_location_inits<'a, 'gcx, 'tcx, F>(
207     tcx: TyCtxt<'a, 'gcx, 'tcx>,
208     mir: &Body<'tcx>,
209     move_data: &MoveData<'tcx>,
210     loc: Location,
211     mut callback: F)
212     where F: FnMut(MovePathIndex)
213 {
214     for ii in &move_data.init_loc_map[loc] {
215         let init = move_data.inits[*ii];
216         match init.kind {
217             InitKind::Deep => {
218                 let path = init.path;
219
220                 on_all_children_bits(tcx, mir, move_data,
221                                     path,
222                                     &mut callback)
223             },
224             InitKind::Shallow => {
225                 let mpi = init.path;
226                 callback(mpi);
227             }
228             InitKind::NonPanicPathOnly => (),
229         }
230     }
231 }