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