]>
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, | |
139 | is_index: match elem { | |
140 | ProjectionElem::Index(..) => true, | |
141 | _ => false, | |
142 | }, | |
143 | }, | |
144 | )); | |
145 | } | |
ba9703b0 XL |
146 | |
147 | ty::Array(..) => { | |
148 | if let ProjectionElem::Index(..) = elem { | |
dc9dc135 XL |
149 | return Err(MoveError::cannot_move_out_of( |
150 | self.loc, | |
e1599b0c XL |
151 | InteriorOfSliceOrArray { ty: place_ty, is_index: true }, |
152 | )); | |
153 | } | |
ba9703b0 XL |
154 | } |
155 | ||
e1599b0c XL |
156 | _ => {} |
157 | }; | |
dc9dc135 | 158 | |
60c5eb7d | 159 | if union_path.is_none() { |
dfeec247 XL |
160 | base = self.add_move_path(base, elem, |tcx| Place { |
161 | local: place.local, | |
162 | projection: tcx.intern_place_elems(&place.projection[..i + 1]), | |
60c5eb7d XL |
163 | }); |
164 | } | |
e1599b0c | 165 | } |
dc9dc135 | 166 | |
60c5eb7d XL |
167 | if let Some(base) = union_path { |
168 | // Move out of union - always move the entire union. | |
169 | Err(MoveError::UnionMove { path: base }) | |
170 | } else { | |
171 | Ok(base) | |
172 | } | |
173 | } | |
174 | ||
175 | fn add_move_path( | |
176 | &mut self, | |
177 | base: MovePathIndex, | |
f9f354fc | 178 | elem: PlaceElem<'tcx>, |
60c5eb7d XL |
179 | mk_place: impl FnOnce(TyCtxt<'tcx>) -> Place<'tcx>, |
180 | ) -> MovePathIndex { | |
181 | let MoveDataBuilder { | |
182 | data: MoveData { rev_lookup, move_paths, path_map, init_path_map, .. }, | |
183 | tcx, | |
184 | .. | |
185 | } = self.builder; | |
dfeec247 | 186 | *rev_lookup.projections.entry((base, elem.lift())).or_insert_with(move || { |
ba9703b0 | 187 | MoveDataBuilder::new_move_path( |
dfeec247 XL |
188 | move_paths, |
189 | path_map, | |
190 | init_path_map, | |
191 | Some(base), | |
192 | mk_place(*tcx), | |
ba9703b0 | 193 | ) |
dfeec247 | 194 | }) |
3b2f2976 XL |
195 | } |
196 | ||
ba9703b0 | 197 | fn create_move_path(&mut self, place: Place<'tcx>) { |
94b46f34 XL |
198 | // This is an non-moving access (such as an overwrite or |
199 | // drop), so this not being a valid move path is OK. | |
ff7c6d11 | 200 | let _ = self.move_path_for(place); |
3b2f2976 | 201 | } |
ea8adc8c | 202 | } |
3b2f2976 | 203 | |
dc9dc135 | 204 | impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { |
b7449926 | 205 | fn finalize( |
e1599b0c | 206 | self, |
b7449926 | 207 | ) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { |
3b2f2976 | 208 | debug!("{}", { |
dc9dc135 | 209 | debug!("moves for {:?}:", self.body.span); |
3b2f2976 XL |
210 | for (j, mo) in self.data.moves.iter_enumerated() { |
211 | debug!(" {:?} = {:?}", j, mo); | |
212 | } | |
dc9dc135 | 213 | debug!("move paths for {:?}:", self.body.span); |
3b2f2976 XL |
214 | for (j, path) in self.data.move_paths.iter_enumerated() { |
215 | debug!(" {:?} = {:?}", j, path); | |
216 | } | |
217 | "done dumping moves" | |
218 | }); | |
ea8adc8c | 219 | |
e1599b0c | 220 | if !self.errors.is_empty() { Err((self.data, self.errors)) } else { Ok(self.data) } |
3b2f2976 XL |
221 | } |
222 | } | |
223 | ||
dc9dc135 XL |
224 | pub(super) fn gather_moves<'tcx>( |
225 | body: &Body<'tcx>, | |
226 | tcx: TyCtxt<'tcx>, | |
60c5eb7d | 227 | param_env: ty::ParamEnv<'tcx>, |
b7449926 | 228 | ) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { |
60c5eb7d | 229 | let mut builder = MoveDataBuilder::new(body, tcx, param_env); |
ff7c6d11 XL |
230 | |
231 | builder.gather_args(); | |
3b2f2976 | 232 | |
dc9dc135 | 233 | for (bb, block) in body.basic_blocks().iter_enumerated() { |
3b2f2976 XL |
234 | for (i, stmt) in block.statements.iter().enumerate() { |
235 | let source = Location { block: bb, statement_index: i }; | |
236 | builder.gather_statement(source, stmt); | |
237 | } | |
238 | ||
e1599b0c | 239 | let terminator_loc = Location { block: bb, statement_index: block.statements.len() }; |
3b2f2976 XL |
240 | builder.gather_terminator(terminator_loc, block.terminator()); |
241 | } | |
242 | ||
243 | builder.finalize() | |
244 | } | |
245 | ||
dc9dc135 | 246 | impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { |
ff7c6d11 | 247 | fn gather_args(&mut self) { |
dc9dc135 | 248 | for arg in self.body.args_iter() { |
ff7c6d11 | 249 | let path = self.data.rev_lookup.locals[arg]; |
ff7c6d11 XL |
250 | |
251 | let init = self.data.inits.push(Init { | |
e1599b0c XL |
252 | path, |
253 | kind: InitKind::Deep, | |
254 | location: InitLocation::Argument(arg), | |
ff7c6d11 XL |
255 | }); |
256 | ||
e1599b0c | 257 | debug!("gather_args: adding init {:?} of {:?} for argument {:?}", init, path, arg); |
ff7c6d11 XL |
258 | |
259 | self.data.init_path_map[path].push(init); | |
260 | } | |
261 | } | |
262 | ||
3b2f2976 XL |
263 | fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) { |
264 | debug!("gather_statement({:?}, {:?})", loc, stmt); | |
ea8adc8c XL |
265 | (Gatherer { builder: self, loc }).gather_statement(stmt); |
266 | } | |
267 | ||
268 | fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) { | |
269 | debug!("gather_terminator({:?}, {:?})", loc, term); | |
270 | (Gatherer { builder: self, loc }).gather_terminator(term); | |
271 | } | |
272 | } | |
273 | ||
dc9dc135 XL |
274 | struct Gatherer<'b, 'a, 'tcx> { |
275 | builder: &'b mut MoveDataBuilder<'a, 'tcx>, | |
ea8adc8c XL |
276 | loc: Location, |
277 | } | |
278 | ||
dc9dc135 | 279 | impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { |
ea8adc8c | 280 | fn gather_statement(&mut self, stmt: &Statement<'tcx>) { |
ba9703b0 XL |
281 | match &stmt.kind { |
282 | StatementKind::Assign(box (place, rval)) => { | |
283 | self.create_move_path(*place); | |
3b2f2976 XL |
284 | if let RvalueInitializationState::Shallow = rval.initialization_state() { |
285 | // Box starts out uninitialized - need to create a separate | |
286 | // move-path for the interior so it will be separate from | |
287 | // the exterior. | |
ba9703b0 | 288 | self.create_move_path(self.builder.tcx.mk_place_deref(*place)); |
416331ca | 289 | self.gather_init(place.as_ref(), InitKind::Shallow); |
ff7c6d11 | 290 | } else { |
416331ca | 291 | self.gather_init(place.as_ref(), InitKind::Deep); |
3b2f2976 | 292 | } |
ea8adc8c | 293 | self.gather_rvalue(rval); |
3b2f2976 | 294 | } |
ba9703b0 XL |
295 | StatementKind::FakeRead(_, place) => { |
296 | self.create_move_path(**place); | |
94b46f34 | 297 | } |
ba9703b0 | 298 | StatementKind::LlvmInlineAsm(ref asm) => { |
532ac7d7 | 299 | for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) { |
ff7c6d11 | 300 | if !kind.is_indirect { |
416331ca | 301 | self.gather_init(output.as_ref(), InitKind::Deep); |
ff7c6d11 XL |
302 | } |
303 | } | |
532ac7d7 | 304 | for (_, input) in asm.inputs.iter() { |
ff7c6d11 XL |
305 | self.gather_operand(input); |
306 | } | |
307 | } | |
abe05a73 XL |
308 | StatementKind::StorageLive(_) => {} |
309 | StatementKind::StorageDead(local) => { | |
ba9703b0 | 310 | self.gather_move(Place::from(*local)); |
abe05a73 | 311 | } |
e1599b0c XL |
312 | StatementKind::SetDiscriminant { .. } => { |
313 | span_bug!( | |
314 | stmt.source_info.span, | |
315 | "SetDiscriminant should not exist during borrowck" | |
316 | ); | |
3b2f2976 | 317 | } |
e1599b0c XL |
318 | StatementKind::Retag { .. } |
319 | | StatementKind::AscribeUserType(..) | |
3dfed10e | 320 | | StatementKind::Coverage(..) |
6a06907d | 321 | | StatementKind::CopyNonOverlapping(..) |
e1599b0c | 322 | | StatementKind::Nop => {} |
3b2f2976 XL |
323 | } |
324 | } | |
325 | ||
ea8adc8c | 326 | fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { |
3b2f2976 | 327 | match *rvalue { |
f9f354fc | 328 | Rvalue::ThreadLocalRef(_) => {} // not-a-move |
e1599b0c XL |
329 | Rvalue::Use(ref operand) |
330 | | Rvalue::Repeat(ref operand, _) | |
331 | | Rvalue::Cast(_, ref operand, _) | |
332 | | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand), | |
6a06907d XL |
333 | Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) |
334 | | Rvalue::CheckedBinaryOp(ref _binop, box (ref lhs, ref rhs)) => { | |
ea8adc8c XL |
335 | self.gather_operand(lhs); |
336 | self.gather_operand(rhs); | |
3b2f2976 XL |
337 | } |
338 | Rvalue::Aggregate(ref _kind, ref operands) => { | |
339 | for operand in operands { | |
ea8adc8c | 340 | self.gather_operand(operand); |
3b2f2976 XL |
341 | } |
342 | } | |
e1599b0c | 343 | Rvalue::Ref(..) |
dfeec247 | 344 | | Rvalue::AddressOf(..) |
e1599b0c XL |
345 | | Rvalue::Discriminant(..) |
346 | | Rvalue::Len(..) | |
347 | | Rvalue::NullaryOp(NullOp::SizeOf, _) | |
348 | | Rvalue::NullaryOp(NullOp::Box, _) => { | |
3b2f2976 XL |
349 | // This returns an rvalue with uninitialized contents. We can't |
350 | // move out of it here because it is an rvalue - assignments always | |
ff7c6d11 | 351 | // completely initialize their place. |
3b2f2976 XL |
352 | // |
353 | // However, this does not matter - MIR building is careful to | |
354 | // only emit a shallow free for the partially-initialized | |
355 | // temporary. | |
356 | // | |
357 | // In any case, if we want to fix this, we have to register a | |
358 | // special move and change the `statement_effect` functions. | |
359 | } | |
360 | } | |
361 | } | |
362 | ||
ea8adc8c | 363 | fn gather_terminator(&mut self, term: &Terminator<'tcx>) { |
3b2f2976 | 364 | match term.kind { |
e1599b0c | 365 | TerminatorKind::Goto { target: _ } |
29967ef6 XL |
366 | | TerminatorKind::FalseEdge { .. } |
367 | | TerminatorKind::FalseUnwind { .. } | |
368 | // In some sense returning moves the return place into the current | |
369 | // call's destination, however, since there are no statements after | |
370 | // this that could possibly access the return place, this doesn't | |
371 | // need recording. | |
372 | | TerminatorKind::Return | |
e1599b0c XL |
373 | | TerminatorKind::Resume |
374 | | TerminatorKind::Abort | |
375 | | TerminatorKind::GeneratorDrop | |
e1599b0c | 376 | | TerminatorKind::Unreachable => {} |
3b2f2976 | 377 | |
0531ce1d XL |
378 | TerminatorKind::Assert { ref cond, .. } => { |
379 | self.gather_operand(cond); | |
380 | } | |
381 | ||
382 | TerminatorKind::SwitchInt { ref discr, .. } => { | |
383 | self.gather_operand(discr); | |
3b2f2976 XL |
384 | } |
385 | ||
ba9703b0 | 386 | TerminatorKind::Yield { ref value, resume_arg: place, .. } => { |
ea8adc8c | 387 | self.gather_operand(value); |
74b04a01 XL |
388 | self.create_move_path(place); |
389 | self.gather_init(place.as_ref(), InitKind::Deep); | |
ea8adc8c XL |
390 | } |
391 | ||
f035d41b XL |
392 | TerminatorKind::Drop { place, target: _, unwind: _ } => { |
393 | self.gather_move(place); | |
3b2f2976 | 394 | } |
f035d41b XL |
395 | TerminatorKind::DropAndReplace { place, ref value, .. } => { |
396 | self.create_move_path(place); | |
ea8adc8c | 397 | self.gather_operand(value); |
f035d41b | 398 | self.gather_init(place.as_ref(), InitKind::Deep); |
3b2f2976 | 399 | } |
0bf4aa26 XL |
400 | TerminatorKind::Call { |
401 | ref func, | |
402 | ref args, | |
403 | ref destination, | |
404 | cleanup: _, | |
405 | from_hir_call: _, | |
f035d41b | 406 | fn_span: _, |
0bf4aa26 | 407 | } => { |
ea8adc8c | 408 | self.gather_operand(func); |
3b2f2976 | 409 | for arg in args { |
ea8adc8c | 410 | self.gather_operand(arg); |
3b2f2976 | 411 | } |
ba9703b0 | 412 | if let Some((destination, _bb)) = *destination { |
3b2f2976 | 413 | self.create_move_path(destination); |
416331ca | 414 | self.gather_init(destination.as_ref(), InitKind::NonPanicPathOnly); |
3b2f2976 XL |
415 | } |
416 | } | |
f9f354fc XL |
417 | TerminatorKind::InlineAsm { |
418 | template: _, | |
419 | ref operands, | |
420 | options: _, | |
421 | line_spans: _, | |
422 | destination: _, | |
423 | } => { | |
424 | for op in operands { | |
425 | match *op { | |
426 | InlineAsmOperand::In { reg: _, ref value } | |
427 | | InlineAsmOperand::Const { ref value } => { | |
428 | self.gather_operand(value); | |
429 | } | |
430 | InlineAsmOperand::Out { reg: _, late: _, place, .. } => { | |
431 | if let Some(place) = place { | |
432 | self.create_move_path(place); | |
433 | self.gather_init(place.as_ref(), InitKind::Deep); | |
434 | } | |
435 | } | |
436 | InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => { | |
437 | self.gather_operand(in_value); | |
438 | if let Some(out_place) = out_place { | |
439 | self.create_move_path(out_place); | |
440 | self.gather_init(out_place.as_ref(), InitKind::Deep); | |
441 | } | |
442 | } | |
443 | InlineAsmOperand::SymFn { value: _ } | |
f035d41b | 444 | | InlineAsmOperand::SymStatic { def_id: _ } => {} |
f9f354fc XL |
445 | } |
446 | } | |
447 | } | |
3b2f2976 XL |
448 | } |
449 | } | |
450 | ||
ea8adc8c | 451 | fn gather_operand(&mut self, operand: &Operand<'tcx>) { |
3b2f2976 | 452 | match *operand { |
e1599b0c | 453 | Operand::Constant(..) | Operand::Copy(..) => {} // not-a-move |
ba9703b0 | 454 | Operand::Move(place) => { |
e1599b0c | 455 | // a move |
ff7c6d11 | 456 | self.gather_move(place); |
3b2f2976 XL |
457 | } |
458 | } | |
459 | } | |
460 | ||
ba9703b0 | 461 | fn gather_move(&mut self, place: Place<'tcx>) { |
ff7c6d11 | 462 | debug!("gather_move({:?}, {:?})", self.loc, place); |
3b2f2976 | 463 | |
dfeec247 XL |
464 | if let [ref base @ .., ProjectionElem::Subslice { from, to, from_end: false }] = |
465 | **place.projection | |
466 | { | |
60c5eb7d XL |
467 | // Split `Subslice` patterns into the corresponding list of |
468 | // `ConstIndex` patterns. This is done to ensure that all move paths | |
469 | // are disjoint, which is expected by drop elaboration. | |
dfeec247 XL |
470 | let base_place = |
471 | Place { local: place.local, projection: self.builder.tcx.intern_place_elems(base) }; | |
ba9703b0 | 472 | let base_path = match self.move_path_for(base_place) { |
60c5eb7d XL |
473 | Ok(path) => path, |
474 | Err(MoveError::UnionMove { path }) => { | |
475 | self.record_move(place, path); | |
476 | return; | |
477 | } | |
478 | Err(error @ MoveError::IllegalMove { .. }) => { | |
479 | self.builder.errors.push((base_place, error)); | |
480 | return; | |
481 | } | |
482 | }; | |
483 | let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty; | |
1b1a35ee XL |
484 | let len: u64 = match base_ty.kind() { |
485 | ty::Array(_, size) => size.eval_usize(self.builder.tcx, self.builder.param_env), | |
60c5eb7d XL |
486 | _ => bug!("from_end: false slice pattern of non-array type"), |
487 | }; | |
488 | for offset in from..to { | |
dfeec247 XL |
489 | let elem = |
490 | ProjectionElem::ConstantIndex { offset, min_length: len, from_end: false }; | |
ba9703b0 | 491 | let path = |
f9f354fc | 492 | self.add_move_path(base_path, elem, |tcx| tcx.mk_place_elem(base_place, elem)); |
60c5eb7d | 493 | self.record_move(place, path); |
3b2f2976 | 494 | } |
60c5eb7d XL |
495 | } else { |
496 | match self.move_path_for(place) { | |
497 | Ok(path) | Err(MoveError::UnionMove { path }) => self.record_move(place, path), | |
498 | Err(error @ MoveError::IllegalMove { .. }) => { | |
ba9703b0 | 499 | self.builder.errors.push((place, error)); |
60c5eb7d XL |
500 | } |
501 | }; | |
502 | } | |
503 | } | |
3b2f2976 | 504 | |
ba9703b0 | 505 | fn record_move(&mut self, place: Place<'tcx>, path: MovePathIndex) { |
74b04a01 | 506 | let move_out = self.builder.data.moves.push(MoveOut { path, source: self.loc }); |
e1599b0c XL |
507 | debug!( |
508 | "gather_move({:?}, {:?}): adding move {:?} of {:?}", | |
509 | self.loc, place, move_out, path | |
510 | ); | |
ea8adc8c XL |
511 | self.builder.data.path_map[path].push(move_out); |
512 | self.builder.data.loc_map[self.loc].push(move_out); | |
3b2f2976 | 513 | } |
ff7c6d11 | 514 | |
74b04a01 | 515 | fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) { |
ff7c6d11 XL |
516 | debug!("gather_init({:?}, {:?})", self.loc, place); |
517 | ||
416331ca XL |
518 | let mut place = place; |
519 | ||
520 | // Check if we are assigning into a field of a union, if so, lookup the place | |
521 | // of the union so it is marked as initialized again. | |
5869c6ff XL |
522 | if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() { |
523 | if let ty::Adt(def, _) = place_base.ty(self.builder.body, self.builder.tcx).ty.kind() { | |
416331ca | 524 | if def.is_union() { |
5869c6ff | 525 | place = place_base; |
416331ca XL |
526 | } |
527 | } | |
528 | } | |
a1dfa0c6 | 529 | |
ff7c6d11 XL |
530 | if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(place) { |
531 | let init = self.builder.data.inits.push(Init { | |
b7449926 | 532 | location: InitLocation::Statement(self.loc), |
ff7c6d11 XL |
533 | path, |
534 | kind, | |
535 | }); | |
536 | ||
e1599b0c XL |
537 | debug!( |
538 | "gather_init({:?}, {:?}): adding init {:?} of {:?}", | |
539 | self.loc, place, init, path | |
540 | ); | |
ff7c6d11 XL |
541 | |
542 | self.builder.data.init_path_map[path].push(init); | |
543 | self.builder.data.init_loc_map[self.loc].push(init); | |
544 | } | |
545 | } | |
3b2f2976 | 546 | } |