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