]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir_dataflow/src/move_paths/builder.rs
bump version to 1.79.0+dfsg1-1~bpo12+pve2
[rustc.git] / compiler / rustc_mir_dataflow / src / move_paths / builder.rs
CommitLineData
49aad941 1use rustc_index::IndexVec;
ed00b5ec 2use rustc_middle::mir::tcx::{PlaceTy, RvalueInitializationState};
ba9703b0 3use rustc_middle::mir::*;
c620b35d 4use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
e1599b0c 5use smallvec::{smallvec, SmallVec};
3b2f2976 6
3b2f2976
XL
7use std::mem;
8
9use super::abs_domain::Lift;
ed00b5ec 10use super::{Init, InitIndex, InitKind, InitLocation, LookupResult};
e1599b0c
XL
11use super::{
12 LocationMap, MoveData, MoveOut, MoveOutIndex, MovePath, MovePathIndex, MovePathLookup,
13};
3b2f2976 14
ed00b5ec 15struct 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
23impl<'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
78fn 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
102enum MovePathResult {
103 Path(MovePathIndex),
104 Union(MovePathIndex),
105 Error,
ea8adc8c 106}
3b2f2976 107
ed00b5ec 108impl<'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
288impl<'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
306pub(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 329impl<'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
357struct Gatherer<'b, 'a, 'tcx, F> {
358 builder: &'b mut MoveDataBuilder<'a, 'tcx, F>,
ea8adc8c
XL
359 loc: Location,
360}
361
ed00b5ec 362impl<'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}