]>
Commit | Line | Data |
---|---|---|
49aad941 | 1 | use rustc_index::IndexVec; |
ed00b5ec | 2 | use rustc_middle::mir::tcx::{PlaceTy, RvalueInitializationState}; |
ba9703b0 | 3 | use rustc_middle::mir::*; |
c620b35d | 4 | use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; |
e1599b0c | 5 | use smallvec::{smallvec, SmallVec}; |
3b2f2976 | 6 | |
3b2f2976 XL |
7 | use std::mem; |
8 | ||
9 | use super::abs_domain::Lift; | |
ed00b5ec | 10 | use super::{Init, InitIndex, InitKind, InitLocation, LookupResult}; |
e1599b0c XL |
11 | use super::{ |
12 | LocationMap, MoveData, MoveOut, MoveOutIndex, MovePath, MovePathIndex, MovePathLookup, | |
13 | }; | |
3b2f2976 | 14 | |
ed00b5ec | 15 | struct MoveDataBuilder<'a, 'tcx, F> { |
dc9dc135 XL |
16 | body: &'a Body<'tcx>, |
17 | tcx: TyCtxt<'tcx>, | |
60c5eb7d | 18 | param_env: ty::ParamEnv<'tcx>, |
3b2f2976 | 19 | data: MoveData<'tcx>, |
ed00b5ec | 20 | filter: F, |
3b2f2976 XL |
21 | } |
22 | ||
ed00b5ec FG |
23 | impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { |
24 | fn new( | |
25 | body: &'a Body<'tcx>, | |
26 | tcx: TyCtxt<'tcx>, | |
27 | param_env: ty::ParamEnv<'tcx>, | |
28 | filter: F, | |
29 | ) -> Self { | |
3b2f2976 XL |
30 | let mut move_paths = IndexVec::new(); |
31 | let mut path_map = IndexVec::new(); | |
ff7c6d11 | 32 | let mut init_path_map = IndexVec::new(); |
3b2f2976 | 33 | |
ed00b5ec FG |
34 | let locals = body |
35 | .local_decls | |
36 | .iter_enumerated() | |
37 | .map(|(i, l)| { | |
38 | if l.is_deref_temp() { | |
39 | return None; | |
40 | } | |
41 | if filter(l.ty) { | |
42 | Some(new_move_path( | |
43 | &mut move_paths, | |
44 | &mut path_map, | |
45 | &mut init_path_map, | |
46 | None, | |
47 | Place::from(i), | |
48 | )) | |
49 | } else { | |
50 | None | |
51 | } | |
52 | }) | |
53 | .collect(); | |
54 | ||
3b2f2976 | 55 | MoveDataBuilder { |
dc9dc135 | 56 | body, |
3b2f2976 | 57 | tcx, |
60c5eb7d | 58 | param_env, |
3b2f2976 XL |
59 | data: MoveData { |
60 | moves: IndexVec::new(), | |
dc9dc135 | 61 | loc_map: LocationMap::new(body), |
3b2f2976 | 62 | rev_lookup: MovePathLookup { |
ed00b5ec | 63 | locals, |
0bf4aa26 | 64 | projections: Default::default(), |
add651ee | 65 | un_derefer: Default::default(), |
3b2f2976 XL |
66 | }, |
67 | move_paths, | |
68 | path_map, | |
ff7c6d11 | 69 | inits: IndexVec::new(), |
dc9dc135 | 70 | init_loc_map: LocationMap::new(body), |
ff7c6d11 | 71 | init_path_map, |
e1599b0c | 72 | }, |
ed00b5ec | 73 | filter, |
3b2f2976 XL |
74 | } |
75 | } | |
ed00b5ec | 76 | } |
3b2f2976 | 77 | |
ed00b5ec FG |
78 | fn new_move_path<'tcx>( |
79 | move_paths: &mut IndexVec<MovePathIndex, MovePath<'tcx>>, | |
80 | path_map: &mut IndexVec<MovePathIndex, SmallVec<[MoveOutIndex; 4]>>, | |
81 | init_path_map: &mut IndexVec<MovePathIndex, SmallVec<[InitIndex; 4]>>, | |
82 | parent: Option<MovePathIndex>, | |
83 | place: Place<'tcx>, | |
84 | ) -> MovePathIndex { | |
85 | let move_path = | |
86 | move_paths.push(MovePath { next_sibling: None, first_child: None, parent, place }); | |
87 | ||
88 | if let Some(parent) = parent { | |
89 | let next_sibling = mem::replace(&mut move_paths[parent].first_child, Some(move_path)); | |
90 | move_paths[move_path].next_sibling = next_sibling; | |
91 | } | |
3b2f2976 | 92 | |
ed00b5ec FG |
93 | let path_map_ent = path_map.push(smallvec![]); |
94 | assert_eq!(path_map_ent, move_path); | |
3b2f2976 | 95 | |
ed00b5ec FG |
96 | let init_path_map_ent = init_path_map.push(smallvec![]); |
97 | assert_eq!(init_path_map_ent, move_path); | |
ff7c6d11 | 98 | |
ed00b5ec FG |
99 | move_path |
100 | } | |
ff7c6d11 | 101 | |
ed00b5ec FG |
102 | enum MovePathResult { |
103 | Path(MovePathIndex), | |
104 | Union(MovePathIndex), | |
105 | Error, | |
ea8adc8c | 106 | } |
3b2f2976 | 107 | |
ed00b5ec | 108 | impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { |
ff7c6d11 XL |
109 | /// This creates a MovePath for a given place, returning an `MovePathError` |
110 | /// if that place can't be moved from. | |
3b2f2976 | 111 | /// |
ff7c6d11 | 112 | /// NOTE: places behind references *do not* get a move path, which is |
3b2f2976 XL |
113 | /// problematic for borrowck. |
114 | /// | |
115 | /// Maybe we should have separate "borrowck" and "moveck" modes. | |
ed00b5ec | 116 | fn move_path_for(&mut self, place: Place<'tcx>) -> MovePathResult { |
add651ee | 117 | let data = &mut self.builder.data; |
064997fb | 118 | |
ff7c6d11 | 119 | debug!("lookup({:?})", place); |
ed00b5ec FG |
120 | let Some(mut base) = data.rev_lookup.find_local(place.local) else { |
121 | return MovePathResult::Error; | |
122 | }; | |
dc9dc135 | 123 | |
60c5eb7d XL |
124 | // The move path index of the first union that we find. Once this is |
125 | // some we stop creating child move paths, since moves from unions | |
126 | // move the whole thing. | |
127 | // We continue looking for other move errors though so that moving | |
128 | // from `*(u.f: &_)` isn't allowed. | |
129 | let mut union_path = None; | |
130 | ||
add651ee FG |
131 | for (place_ref, elem) in data.rev_lookup.un_derefer.iter_projections(place.as_ref()) { |
132 | let body = self.builder.body; | |
133 | let tcx = self.builder.tcx; | |
134 | let place_ty = place_ref.ty(body, tcx).ty; | |
c620b35d FG |
135 | if place_ty.references_error() { |
136 | return MovePathResult::Error; | |
137 | } | |
781aab86 FG |
138 | match elem { |
139 | ProjectionElem::Deref => match place_ty.kind() { | |
140 | ty::Ref(..) | ty::RawPtr(..) => { | |
ed00b5ec | 141 | return MovePathResult::Error; |
781aab86 FG |
142 | } |
143 | ty::Adt(adt, _) => { | |
144 | if !adt.is_box() { | |
145 | bug!("Adt should be a box type when Place is deref"); | |
146 | } | |
147 | } | |
148 | ty::Bool | |
149 | | ty::Char | |
150 | | ty::Int(_) | |
151 | | ty::Uint(_) | |
152 | | ty::Float(_) | |
153 | | ty::Foreign(_) | |
154 | | ty::Str | |
155 | | ty::Array(_, _) | |
e8be2606 | 156 | | ty::Pat(_, _) |
781aab86 FG |
157 | | ty::Slice(_) |
158 | | ty::FnDef(_, _) | |
159 | | ty::FnPtr(_) | |
160 | | ty::Dynamic(_, _, _) | |
c620b35d FG |
161 | | ty::Closure(..) |
162 | | ty::CoroutineClosure(..) | |
c0240ec0 | 163 | | ty::Coroutine(_, _) |
ed00b5ec | 164 | | ty::CoroutineWitness(..) |
781aab86 FG |
165 | | ty::Never |
166 | | ty::Tuple(_) | |
167 | | ty::Alias(_, _) | |
168 | | ty::Param(_) | |
169 | | ty::Bound(_, _) | |
170 | | ty::Infer(_) | |
171 | | ty::Error(_) | |
172 | | ty::Placeholder(_) => { | |
173 | bug!("When Place is Deref it's type shouldn't be {place_ty:#?}") | |
174 | } | |
175 | }, | |
176 | ProjectionElem::Field(_, _) => match place_ty.kind() { | |
177 | ty::Adt(adt, _) => { | |
178 | if adt.has_dtor(tcx) { | |
ed00b5ec | 179 | return MovePathResult::Error; |
781aab86 FG |
180 | } |
181 | if adt.is_union() { | |
182 | union_path.get_or_insert(base); | |
183 | } | |
184 | } | |
c620b35d FG |
185 | ty::Closure(..) |
186 | | ty::CoroutineClosure(..) | |
187 | | ty::Coroutine(_, _) | |
188 | | ty::Tuple(_) => (), | |
781aab86 FG |
189 | ty::Bool |
190 | | ty::Char | |
191 | | ty::Int(_) | |
192 | | ty::Uint(_) | |
193 | | ty::Float(_) | |
194 | | ty::Foreign(_) | |
195 | | ty::Str | |
196 | | ty::Array(_, _) | |
e8be2606 | 197 | | ty::Pat(_, _) |
781aab86 | 198 | | ty::Slice(_) |
e8be2606 | 199 | | ty::RawPtr(_, _) |
781aab86 FG |
200 | | ty::Ref(_, _, _) |
201 | | ty::FnDef(_, _) | |
202 | | ty::FnPtr(_) | |
203 | | ty::Dynamic(_, _, _) | |
ed00b5ec | 204 | | ty::CoroutineWitness(..) |
781aab86 FG |
205 | | ty::Never |
206 | | ty::Alias(_, _) | |
207 | | ty::Param(_) | |
208 | | ty::Bound(_, _) | |
209 | | ty::Infer(_) | |
210 | | ty::Error(_) | |
211 | | ty::Placeholder(_) => bug!( | |
212 | "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}" | |
213 | ), | |
214 | }, | |
215 | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { | |
216 | match place_ty.kind() { | |
217 | ty::Slice(_) => { | |
ed00b5ec | 218 | return MovePathResult::Error; |
781aab86 FG |
219 | } |
220 | ty::Array(_, _) => (), | |
221 | _ => bug!("Unexpected type {:#?}", place_ty.is_array()), | |
222 | } | |
add651ee | 223 | } |
781aab86 | 224 | ProjectionElem::Index(_) => match place_ty.kind() { |
ed00b5ec FG |
225 | ty::Array(..) | ty::Slice(_) => { |
226 | return MovePathResult::Error; | |
781aab86 FG |
227 | } |
228 | _ => bug!("Unexpected type {place_ty:#?}"), | |
229 | }, | |
230 | // `OpaqueCast`:Only transmutes the type, so no moves there. | |
231 | // `Downcast` :Only changes information about a `Place` without moving. | |
232 | // `Subtype` :Only transmutes the type, so moves. | |
233 | // So it's safe to skip these. | |
234 | ProjectionElem::OpaqueCast(_) | |
235 | | ProjectionElem::Subtype(_) | |
236 | | ProjectionElem::Downcast(_, _) => (), | |
237 | } | |
ed00b5ec FG |
238 | let elem_ty = PlaceTy::from_ty(place_ty).projection_ty(tcx, elem).ty; |
239 | if !(self.builder.filter)(elem_ty) { | |
240 | return MovePathResult::Error; | |
241 | } | |
add651ee FG |
242 | if union_path.is_none() { |
243 | // inlined from add_move_path because of a borrowck conflict with the iterator | |
244 | base = | |
245 | *data.rev_lookup.projections.entry((base, elem.lift())).or_insert_with(|| { | |
ed00b5ec | 246 | new_move_path( |
add651ee FG |
247 | &mut data.move_paths, |
248 | &mut data.path_map, | |
249 | &mut data.init_path_map, | |
250 | Some(base), | |
251 | place_ref.project_deeper(&[elem], tcx), | |
252 | ) | |
253 | }) | |
60c5eb7d | 254 | } |
e1599b0c | 255 | } |
dc9dc135 | 256 | |
60c5eb7d XL |
257 | if let Some(base) = union_path { |
258 | // Move out of union - always move the entire union. | |
ed00b5ec | 259 | MovePathResult::Union(base) |
60c5eb7d | 260 | } else { |
ed00b5ec | 261 | MovePathResult::Path(base) |
60c5eb7d XL |
262 | } |
263 | } | |
264 | ||
265 | fn add_move_path( | |
266 | &mut self, | |
267 | base: MovePathIndex, | |
f9f354fc | 268 | elem: PlaceElem<'tcx>, |
60c5eb7d XL |
269 | mk_place: impl FnOnce(TyCtxt<'tcx>) -> Place<'tcx>, |
270 | ) -> MovePathIndex { | |
271 | let MoveDataBuilder { | |
272 | data: MoveData { rev_lookup, move_paths, path_map, init_path_map, .. }, | |
273 | tcx, | |
274 | .. | |
275 | } = self.builder; | |
dfeec247 | 276 | *rev_lookup.projections.entry((base, elem.lift())).or_insert_with(move || { |
ed00b5ec | 277 | new_move_path(move_paths, path_map, init_path_map, Some(base), mk_place(*tcx)) |
dfeec247 | 278 | }) |
3b2f2976 XL |
279 | } |
280 | ||
ba9703b0 | 281 | fn create_move_path(&mut self, place: Place<'tcx>) { |
94b46f34 XL |
282 | // This is an non-moving access (such as an overwrite or |
283 | // drop), so this not being a valid move path is OK. | |
ff7c6d11 | 284 | let _ = self.move_path_for(place); |
3b2f2976 | 285 | } |
ea8adc8c | 286 | } |
3b2f2976 | 287 | |
ed00b5ec FG |
288 | impl<'a, 'tcx, F> MoveDataBuilder<'a, 'tcx, F> { |
289 | fn finalize(self) -> MoveData<'tcx> { | |
3b2f2976 | 290 | debug!("{}", { |
dc9dc135 | 291 | debug!("moves for {:?}:", self.body.span); |
3b2f2976 XL |
292 | for (j, mo) in self.data.moves.iter_enumerated() { |
293 | debug!(" {:?} = {:?}", j, mo); | |
294 | } | |
dc9dc135 | 295 | debug!("move paths for {:?}:", self.body.span); |
3b2f2976 XL |
296 | for (j, path) in self.data.move_paths.iter_enumerated() { |
297 | debug!(" {:?} = {:?}", j, path); | |
298 | } | |
299 | "done dumping moves" | |
300 | }); | |
ea8adc8c | 301 | |
ed00b5ec | 302 | self.data |
3b2f2976 XL |
303 | } |
304 | } | |
305 | ||
dc9dc135 XL |
306 | pub(super) fn gather_moves<'tcx>( |
307 | body: &Body<'tcx>, | |
308 | tcx: TyCtxt<'tcx>, | |
60c5eb7d | 309 | param_env: ty::ParamEnv<'tcx>, |
ed00b5ec FG |
310 | filter: impl Fn(Ty<'tcx>) -> bool, |
311 | ) -> MoveData<'tcx> { | |
312 | let mut builder = MoveDataBuilder::new(body, tcx, param_env, filter); | |
ff7c6d11 XL |
313 | |
314 | builder.gather_args(); | |
3b2f2976 | 315 | |
f2b60f7d | 316 | for (bb, block) in body.basic_blocks.iter_enumerated() { |
3b2f2976 XL |
317 | for (i, stmt) in block.statements.iter().enumerate() { |
318 | let source = Location { block: bb, statement_index: i }; | |
319 | builder.gather_statement(source, stmt); | |
320 | } | |
321 | ||
e1599b0c | 322 | let terminator_loc = Location { block: bb, statement_index: block.statements.len() }; |
3b2f2976 XL |
323 | builder.gather_terminator(terminator_loc, block.terminator()); |
324 | } | |
325 | ||
326 | builder.finalize() | |
327 | } | |
328 | ||
ed00b5ec | 329 | impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { |
ff7c6d11 | 330 | fn gather_args(&mut self) { |
dc9dc135 | 331 | for arg in self.body.args_iter() { |
ed00b5ec FG |
332 | if let Some(path) = self.data.rev_lookup.find_local(arg) { |
333 | let init = self.data.inits.push(Init { | |
334 | path, | |
335 | kind: InitKind::Deep, | |
336 | location: InitLocation::Argument(arg), | |
337 | }); | |
ff7c6d11 | 338 | |
ed00b5ec | 339 | debug!("gather_args: adding init {:?} of {:?} for argument {:?}", init, path, arg); |
ff7c6d11 | 340 | |
ed00b5ec FG |
341 | self.data.init_path_map[path].push(init); |
342 | } | |
ff7c6d11 XL |
343 | } |
344 | } | |
345 | ||
3b2f2976 XL |
346 | fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) { |
347 | debug!("gather_statement({:?}, {:?})", loc, stmt); | |
ea8adc8c XL |
348 | (Gatherer { builder: self, loc }).gather_statement(stmt); |
349 | } | |
350 | ||
351 | fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) { | |
352 | debug!("gather_terminator({:?}, {:?})", loc, term); | |
353 | (Gatherer { builder: self, loc }).gather_terminator(term); | |
354 | } | |
355 | } | |
356 | ||
ed00b5ec FG |
357 | struct Gatherer<'b, 'a, 'tcx, F> { |
358 | builder: &'b mut MoveDataBuilder<'a, 'tcx, F>, | |
ea8adc8c XL |
359 | loc: Location, |
360 | } | |
361 | ||
ed00b5ec | 362 | impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { |
ea8adc8c | 363 | fn gather_statement(&mut self, stmt: &Statement<'tcx>) { |
ba9703b0 | 364 | match &stmt.kind { |
064997fb | 365 | StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => { |
add651ee FG |
366 | let local = place.as_local().unwrap(); |
367 | assert!(self.builder.body.local_decls[local].is_deref_temp()); | |
368 | ||
369 | let rev_lookup = &mut self.builder.data.rev_lookup; | |
370 | ||
371 | rev_lookup.un_derefer.insert(local, reffed.as_ref()); | |
372 | let base_local = rev_lookup.un_derefer.deref_chain(local).first().unwrap().local; | |
373 | rev_lookup.locals[local] = rev_lookup.locals[base_local]; | |
064997fb | 374 | } |
ba9703b0 XL |
375 | StatementKind::Assign(box (place, rval)) => { |
376 | self.create_move_path(*place); | |
3b2f2976 XL |
377 | if let RvalueInitializationState::Shallow = rval.initialization_state() { |
378 | // Box starts out uninitialized - need to create a separate | |
379 | // move-path for the interior so it will be separate from | |
380 | // the exterior. | |
ba9703b0 | 381 | self.create_move_path(self.builder.tcx.mk_place_deref(*place)); |
416331ca | 382 | self.gather_init(place.as_ref(), InitKind::Shallow); |
ff7c6d11 | 383 | } else { |
416331ca | 384 | self.gather_init(place.as_ref(), InitKind::Deep); |
3b2f2976 | 385 | } |
ea8adc8c | 386 | self.gather_rvalue(rval); |
3b2f2976 | 387 | } |
cdc7bbd5 XL |
388 | StatementKind::FakeRead(box (_, place)) => { |
389 | self.create_move_path(*place); | |
94b46f34 | 390 | } |
abe05a73 XL |
391 | StatementKind::StorageLive(_) => {} |
392 | StatementKind::StorageDead(local) => { | |
064997fb | 393 | // DerefTemp locals (results of CopyForDeref) don't actually move anything. |
add651ee | 394 | if !self.builder.body.local_decls[*local].is_deref_temp() { |
064997fb FG |
395 | self.gather_move(Place::from(*local)); |
396 | } | |
abe05a73 | 397 | } |
04454e1e | 398 | StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) => { |
e1599b0c XL |
399 | span_bug!( |
400 | stmt.source_info.span, | |
04454e1e | 401 | "SetDiscriminant/Deinit should not exist during borrowck" |
e1599b0c | 402 | ); |
3b2f2976 | 403 | } |
e1599b0c XL |
404 | StatementKind::Retag { .. } |
405 | | StatementKind::AscribeUserType(..) | |
353b0b11 | 406 | | StatementKind::PlaceMention(..) |
3dfed10e | 407 | | StatementKind::Coverage(..) |
f2b60f7d | 408 | | StatementKind::Intrinsic(..) |
9ffffee4 | 409 | | StatementKind::ConstEvalCounter |
e1599b0c | 410 | | StatementKind::Nop => {} |
3b2f2976 XL |
411 | } |
412 | } | |
413 | ||
ea8adc8c | 414 | fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { |
3b2f2976 | 415 | match *rvalue { |
f9f354fc | 416 | Rvalue::ThreadLocalRef(_) => {} // not-a-move |
e1599b0c XL |
417 | Rvalue::Use(ref operand) |
418 | | Rvalue::Repeat(ref operand, _) | |
419 | | Rvalue::Cast(_, ref operand, _) | |
c295e0f8 | 420 | | Rvalue::ShallowInitBox(ref operand, _) |
e1599b0c | 421 | | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand), |
6a06907d XL |
422 | Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) |
423 | | Rvalue::CheckedBinaryOp(ref _binop, box (ref lhs, ref rhs)) => { | |
ea8adc8c XL |
424 | self.gather_operand(lhs); |
425 | self.gather_operand(rhs); | |
3b2f2976 XL |
426 | } |
427 | Rvalue::Aggregate(ref _kind, ref operands) => { | |
428 | for operand in operands { | |
ea8adc8c | 429 | self.gather_operand(operand); |
3b2f2976 XL |
430 | } |
431 | } | |
064997fb | 432 | Rvalue::CopyForDeref(..) => unreachable!(), |
e1599b0c | 433 | Rvalue::Ref(..) |
dfeec247 | 434 | | Rvalue::AddressOf(..) |
e1599b0c XL |
435 | | Rvalue::Discriminant(..) |
436 | | Rvalue::Len(..) | |
c620b35d | 437 | | Rvalue::NullaryOp( |
e8be2606 | 438 | NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbChecks, |
c620b35d FG |
439 | _, |
440 | ) => {} | |
3b2f2976 XL |
441 | } |
442 | } | |
443 | ||
ea8adc8c | 444 | fn gather_terminator(&mut self, term: &Terminator<'tcx>) { |
3b2f2976 | 445 | match term.kind { |
e1599b0c | 446 | TerminatorKind::Goto { target: _ } |
29967ef6 XL |
447 | | TerminatorKind::FalseEdge { .. } |
448 | | TerminatorKind::FalseUnwind { .. } | |
449 | // In some sense returning moves the return place into the current | |
450 | // call's destination, however, since there are no statements after | |
451 | // this that could possibly access the return place, this doesn't | |
452 | // need recording. | |
453 | | TerminatorKind::Return | |
781aab86 FG |
454 | | TerminatorKind::UnwindResume |
455 | | TerminatorKind::UnwindTerminate(_) | |
ed00b5ec | 456 | | TerminatorKind::CoroutineDrop |
9ffffee4 FG |
457 | | TerminatorKind::Unreachable |
458 | | TerminatorKind::Drop { .. } => {} | |
3b2f2976 | 459 | |
0531ce1d XL |
460 | TerminatorKind::Assert { ref cond, .. } => { |
461 | self.gather_operand(cond); | |
462 | } | |
463 | ||
464 | TerminatorKind::SwitchInt { ref discr, .. } => { | |
465 | self.gather_operand(discr); | |
3b2f2976 XL |
466 | } |
467 | ||
ba9703b0 | 468 | TerminatorKind::Yield { ref value, resume_arg: place, .. } => { |
ea8adc8c | 469 | self.gather_operand(value); |
74b04a01 XL |
470 | self.create_move_path(place); |
471 | self.gather_init(place.as_ref(), InitKind::Deep); | |
ea8adc8c | 472 | } |
0bf4aa26 XL |
473 | TerminatorKind::Call { |
474 | ref func, | |
475 | ref args, | |
923072b8 FG |
476 | destination, |
477 | target, | |
353b0b11 | 478 | unwind: _, |
fe692bf9 | 479 | call_source: _, |
f035d41b | 480 | fn_span: _, |
0bf4aa26 | 481 | } => { |
ea8adc8c | 482 | self.gather_operand(func); |
3b2f2976 | 483 | for arg in args { |
c0240ec0 | 484 | self.gather_operand(&arg.node); |
3b2f2976 | 485 | } |
923072b8 | 486 | if let Some(_bb) = target { |
3b2f2976 | 487 | self.create_move_path(destination); |
416331ca | 488 | self.gather_init(destination.as_ref(), InitKind::NonPanicPathOnly); |
3b2f2976 XL |
489 | } |
490 | } | |
f9f354fc XL |
491 | TerminatorKind::InlineAsm { |
492 | template: _, | |
493 | ref operands, | |
494 | options: _, | |
495 | line_spans: _, | |
c620b35d | 496 | targets: _, |
353b0b11 | 497 | unwind: _, |
f9f354fc XL |
498 | } => { |
499 | for op in operands { | |
500 | match *op { | |
501 | InlineAsmOperand::In { reg: _, ref value } | |
cdc7bbd5 | 502 | => { |
f9f354fc XL |
503 | self.gather_operand(value); |
504 | } | |
505 | InlineAsmOperand::Out { reg: _, late: _, place, .. } => { | |
506 | if let Some(place) = place { | |
507 | self.create_move_path(place); | |
508 | self.gather_init(place.as_ref(), InitKind::Deep); | |
509 | } | |
510 | } | |
511 | InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => { | |
512 | self.gather_operand(in_value); | |
513 | if let Some(out_place) = out_place { | |
514 | self.create_move_path(out_place); | |
515 | self.gather_init(out_place.as_ref(), InitKind::Deep); | |
516 | } | |
517 | } | |
cdc7bbd5 XL |
518 | InlineAsmOperand::Const { value: _ } |
519 | | InlineAsmOperand::SymFn { value: _ } | |
c620b35d FG |
520 | | InlineAsmOperand::SymStatic { def_id: _ } |
521 | | InlineAsmOperand::Label { target_index: _ } => {} | |
f9f354fc XL |
522 | } |
523 | } | |
524 | } | |
3b2f2976 XL |
525 | } |
526 | } | |
527 | ||
ea8adc8c | 528 | fn gather_operand(&mut self, operand: &Operand<'tcx>) { |
3b2f2976 | 529 | match *operand { |
e1599b0c | 530 | Operand::Constant(..) | Operand::Copy(..) => {} // not-a-move |
ba9703b0 | 531 | Operand::Move(place) => { |
e1599b0c | 532 | // a move |
ff7c6d11 | 533 | self.gather_move(place); |
3b2f2976 XL |
534 | } |
535 | } | |
536 | } | |
537 | ||
ba9703b0 | 538 | fn gather_move(&mut self, place: Place<'tcx>) { |
ff7c6d11 | 539 | debug!("gather_move({:?}, {:?})", self.loc, place); |
dfeec247 XL |
540 | if let [ref base @ .., ProjectionElem::Subslice { from, to, from_end: false }] = |
541 | **place.projection | |
542 | { | |
60c5eb7d XL |
543 | // Split `Subslice` patterns into the corresponding list of |
544 | // `ConstIndex` patterns. This is done to ensure that all move paths | |
545 | // are disjoint, which is expected by drop elaboration. | |
dfeec247 | 546 | let base_place = |
9ffffee4 | 547 | Place { local: place.local, projection: self.builder.tcx.mk_place_elems(base) }; |
ba9703b0 | 548 | let base_path = match self.move_path_for(base_place) { |
ed00b5ec FG |
549 | MovePathResult::Path(path) => path, |
550 | MovePathResult::Union(path) => { | |
60c5eb7d XL |
551 | self.record_move(place, path); |
552 | return; | |
553 | } | |
ed00b5ec | 554 | MovePathResult::Error => { |
60c5eb7d XL |
555 | return; |
556 | } | |
557 | }; | |
558 | let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty; | |
1b1a35ee | 559 | let len: u64 = match base_ty.kind() { |
9ffffee4 FG |
560 | ty::Array(_, size) => { |
561 | size.eval_target_usize(self.builder.tcx, self.builder.param_env) | |
562 | } | |
60c5eb7d XL |
563 | _ => bug!("from_end: false slice pattern of non-array type"), |
564 | }; | |
565 | for offset in from..to { | |
dfeec247 XL |
566 | let elem = |
567 | ProjectionElem::ConstantIndex { offset, min_length: len, from_end: false }; | |
ba9703b0 | 568 | let path = |
f9f354fc | 569 | self.add_move_path(base_path, elem, |tcx| tcx.mk_place_elem(base_place, elem)); |
60c5eb7d | 570 | self.record_move(place, path); |
3b2f2976 | 571 | } |
60c5eb7d XL |
572 | } else { |
573 | match self.move_path_for(place) { | |
ed00b5ec FG |
574 | MovePathResult::Path(path) | MovePathResult::Union(path) => { |
575 | self.record_move(place, path) | |
60c5eb7d | 576 | } |
ed00b5ec | 577 | MovePathResult::Error => {} |
60c5eb7d XL |
578 | }; |
579 | } | |
580 | } | |
3b2f2976 | 581 | |
ba9703b0 | 582 | fn record_move(&mut self, place: Place<'tcx>, path: MovePathIndex) { |
74b04a01 | 583 | let move_out = self.builder.data.moves.push(MoveOut { path, source: self.loc }); |
e1599b0c XL |
584 | debug!( |
585 | "gather_move({:?}, {:?}): adding move {:?} of {:?}", | |
586 | self.loc, place, move_out, path | |
587 | ); | |
ea8adc8c XL |
588 | self.builder.data.path_map[path].push(move_out); |
589 | self.builder.data.loc_map[self.loc].push(move_out); | |
3b2f2976 | 590 | } |
ff7c6d11 | 591 | |
74b04a01 | 592 | fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) { |
ff7c6d11 XL |
593 | debug!("gather_init({:?}, {:?})", self.loc, place); |
594 | ||
416331ca XL |
595 | let mut place = place; |
596 | ||
597 | // Check if we are assigning into a field of a union, if so, lookup the place | |
598 | // of the union so it is marked as initialized again. | |
5869c6ff | 599 | if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() { |
17df50a5 XL |
600 | if place_base.ty(self.builder.body, self.builder.tcx).ty.is_union() { |
601 | place = place_base; | |
416331ca XL |
602 | } |
603 | } | |
a1dfa0c6 | 604 | |
ff7c6d11 XL |
605 | if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(place) { |
606 | let init = self.builder.data.inits.push(Init { | |
b7449926 | 607 | location: InitLocation::Statement(self.loc), |
ff7c6d11 XL |
608 | path, |
609 | kind, | |
610 | }); | |
611 | ||
e1599b0c XL |
612 | debug!( |
613 | "gather_init({:?}, {:?}): adding init {:?} of {:?}", | |
614 | self.loc, place, init, path | |
615 | ); | |
ff7c6d11 XL |
616 | |
617 | self.builder.data.init_path_map[path].push(init); | |
618 | self.builder.data.init_loc_map[self.loc].push(init); | |
619 | } | |
620 | } | |
3b2f2976 | 621 | } |