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