]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/dataflow/drop_flag_effects.rs
Rollup merge of #68342 - lcnr:type_name_docs, r=Dylan-DPC
[rust.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 }