]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir_build/src/build/expr/as_place.rs
Move handling UpvarRef to PlaceBuilder
[rust.git] / compiler / rustc_mir_build / src / build / expr / as_place.rs
1 //! See docs in build/expr/mod.rs
2
3 use crate::build::expr::category::Category;
4 use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
5 use crate::build::{BlockAnd, BlockAndExtension, Builder};
6 use crate::thir::*;
7 use rustc_hir::def_id::DefId;
8 use rustc_hir::HirId;
9 use rustc_middle::middle::region;
10 use rustc_middle::mir::AssertKind::BoundsCheck;
11 use rustc_middle::mir::*;
12 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance};
13 use rustc_span::Span;
14
15 use rustc_index::vec::Idx;
16
17 /// The "outermost" place that holds this value.
18 #[derive(Copy, Clone)]
19 pub enum PlaceBase {
20     /// Denotes the start of a `Place`.
21     Local(Local),
22
23     /// When building place for an expression within a closure, the place might start off a
24     /// captured path. When `capture_disjoint_fields` is enabled, we might not know the capture
25     /// index (within the desugared closure) of the captured path until most of the projections
26     /// are applied. We use `PlaceBase::Upvar` to keep track of the root variable off of which the
27     /// captured path starts, the closure the capture belongs to and the trait the closure
28     /// implements.
29     ///
30     /// Once we have figured out the capture index, we can convert the place builder to start from
31     /// `PlaceBase::Local`.
32     ///
33     /// Consider the following example
34     /// ```rust
35     /// let t = (10, (10, (10, 10)));
36     ///
37     /// let c = || {
38     ///     println!("{}", t.0.0.0);
39     /// };
40     /// ```
41     /// Here the THIR expression for `t.0.0.0` will be something like
42     ///
43     /// ```
44     /// * Field(0)
45     ///     * Field(0)
46     ///         * Field(0)
47     ///             * UpvarRef(t)
48     /// ```
49     ///
50     /// When `capture_disjoint_fields` is enabled, `t.0.0.0` is captured and we won't be able to
51     /// figure out that it is captured until all the `Field` projections are applied.
52     Upvar {
53         /// HirId of the upvar
54         var_hir_id: HirId,
55         /// DefId of the closure
56         closure_def_id: DefId,
57         /// The trait closure implements, `Fn`, `FnMut`, `FnOnce`
58         closure_kind: ty::ClosureKind },
59 }
60
61 /// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
62 /// place by pushing more and more projections onto the end, and then convert the final set into a
63 /// place using the `into_place` method.
64 ///
65 /// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
66 /// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
67 #[derive(Clone)]
68 struct PlaceBuilder<'tcx> {
69     base: PlaceBase,
70     projection: Vec<PlaceElem<'tcx>>,
71 }
72
73 fn capture_matching_projections<'a, 'tcx>(
74     typeck_results: &'a ty::TypeckResults<'tcx>,
75     var_hir_id: HirId,
76     closure_def_id: DefId,
77     _projections: &Vec<PlaceElem<'tcx>>,
78 ) -> Option<(usize, ty::UpvarCapture<'tcx>)> {
79     typeck_results
80     .closure_captures
81     .get(&closure_def_id)
82     .and_then(|captures| captures.get_full(&var_hir_id))
83     .and_then(|(capture_index, _, _)|{
84         let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local());
85         let capture_kind = typeck_results.upvar_capture(upvar_id);
86         Some((capture_index, capture_kind))
87     })
88 }
89
90 /// Takes a PlaceBuilder and resolves the upvar (if any) within it,
91 /// so that the PlaceBuilder now starts from PlaceBase::Local.
92 ///
93 /// Returns a Result with the error being the HirId of the
94 /// Upvar that was not found.
95 fn to_upvars_resolved_place_builder<'a, 'tcx>(
96     from_builder: PlaceBuilder<'tcx>,
97     tcx: TyCtxt<'tcx>,
98     typeck_results: &'a ty::TypeckResults<'tcx>,
99 ) -> Result<PlaceBuilder<'tcx>, HirId> {
100     match from_builder.base {
101         PlaceBase::Local(_) => Ok(from_builder),
102         PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => {
103             // Captures are represented using fields inside a structure.
104             // This represents accessing self in the closure structure
105             let mut upvar_resolved_place_builder = PlaceBuilder::from(Local::new(1));
106             match closure_kind {
107                 ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
108                     upvar_resolved_place_builder = upvar_resolved_place_builder.deref();
109                 }
110                 ty::ClosureKind::FnOnce => {}
111             }
112
113             let (capture_index, capture_kind) =
114                 if let Some(capture_details) = capture_matching_projections(
115                     typeck_results,
116                     var_hir_id,
117                     closure_def_id,
118                     &from_builder.projection,
119                 ) {
120                     capture_details
121                 } else {
122                     if !tcx.features().capture_disjoint_fields {
123                         bug!(
124                             "No associated capture found for {:?}[{:#?}] even though \
125                             capture_disjoint_fields isn't enabled",
126                             var_hir_id,
127                             from_builder.projection
128                         )
129                     } else {
130                         // FIXME(project-rfc-2229#24): Handle this case properly
131                         debug!(
132                             "No associated capture found for {:?}[{:#?}]",
133                             var_hir_id,
134                             from_builder.projection,
135                         );
136                     }
137                     return Err(var_hir_id);
138                 };
139
140             let closure_ty =
141                 typeck_results.node_type(tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()));
142
143             let substs = match closure_ty.kind() {
144                 ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
145                 ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs),
146                 _ => bug!("Lowering capture for non-closure type {:?}", closure_ty),
147             };
148
149             // Access the capture by accessing the field within the Closure struct.
150             //
151             // We must have inferred the capture types since we are building MIR, therefore
152             // it's safe to call `upvar_tys` and we can unwrap here because
153             // we know that the capture exists and is the `capture_index`-th capture.
154             let var_ty = substs.upvar_tys().nth(capture_index).unwrap();
155
156             upvar_resolved_place_builder = upvar_resolved_place_builder.field(Field::new(capture_index), var_ty);
157
158             // If the variable is captured via ByRef(Immutable/Mutable) Borrow,
159             // we need to deref it
160             upvar_resolved_place_builder = match capture_kind {
161                 ty::UpvarCapture::ByRef(_) => upvar_resolved_place_builder.deref(),
162                 ty::UpvarCapture::ByValue(_) => upvar_resolved_place_builder,
163             };
164
165             let next_projection = 0;
166             let mut curr_projections = from_builder.projection;
167             upvar_resolved_place_builder.projection.extend(
168                 curr_projections.drain(next_projection..));
169
170             Ok(upvar_resolved_place_builder)
171         }
172     }
173 }
174
175 impl<'tcx> PlaceBuilder<'tcx> {
176     fn into_place<'a>(
177         self,
178         tcx: TyCtxt<'tcx>,
179         typeck_results: &'a ty::TypeckResults<'tcx>,
180     ) -> Place<'tcx> {
181         if let PlaceBase::Local(local) = self.base {
182             Place { local, projection: tcx.intern_place_elems(&self.projection) }
183         } else {
184             self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
185         }
186     }
187
188     fn expect_upvars_resolved<'a>(
189         self,
190         tcx: TyCtxt<'tcx>,
191         typeck_results: &'a ty::TypeckResults<'tcx>,
192     ) -> PlaceBuilder<'tcx> {
193         to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap()
194     }
195
196     fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
197         self.project(PlaceElem::Field(f, ty))
198     }
199
200     fn deref(self) -> Self {
201         self.project(PlaceElem::Deref)
202     }
203
204     fn index(self, index: Local) -> Self {
205         self.project(PlaceElem::Index(index))
206     }
207
208     fn project(mut self, elem: PlaceElem<'tcx>) -> Self {
209         self.projection.push(elem);
210         self
211     }
212 }
213
214 impl<'tcx> From<Local> for PlaceBuilder<'tcx> {
215     fn from(local: Local) -> Self {
216         Self { base: PlaceBase::Local(local), projection: Vec::new() }
217     }
218 }
219
220 impl<'tcx> From<PlaceBase> for PlaceBuilder<'tcx> {
221     fn from(base: PlaceBase) -> Self {
222         Self { base, projection: Vec::new() }
223     }
224 }
225
226 impl<'a, 'tcx> Builder<'a, 'tcx> {
227     /// Compile `expr`, yielding a place that we can move from etc.
228     ///
229     /// WARNING: Any user code might:
230     /// * Invalidate any slice bounds checks performed.
231     /// * Change the address that this `Place` refers to.
232     /// * Modify the memory that this place refers to.
233     /// * Invalidate the memory that this place refers to, this will be caught
234     ///   by borrow checking.
235     ///
236     /// Extra care is needed if any user code is allowed to run between calling
237     /// this method and using it, as is the case for `match` and index
238     /// expressions.
239     crate fn as_place<M>(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
240     where
241         M: Mirror<'tcx, Output = Expr<'tcx>>,
242     {
243         let place_builder = unpack!(block = self.as_place_builder(block, expr));
244         block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results()))
245     }
246
247     /// This is used when constructing a compound `Place`, so that we can avoid creating
248     /// intermediate `Place` values until we know the full set of projections.
249     fn as_place_builder<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<PlaceBuilder<'tcx>>
250     where
251         M: Mirror<'tcx, Output = Expr<'tcx>>,
252     {
253         let expr = self.hir.mirror(expr);
254         self.expr_as_place(block, expr, Mutability::Mut, None)
255     }
256
257     /// Compile `expr`, yielding a place that we can move from etc.
258     /// Mutability note: The caller of this method promises only to read from the resulting
259     /// place. The place itself may or may not be mutable:
260     /// * If this expr is a place expr like a.b, then we will return that place.
261     /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
262     crate fn as_read_only_place<M>(
263         &mut self,
264         mut block: BasicBlock,
265         expr: M,
266     ) -> BlockAnd<Place<'tcx>>
267     where
268         M: Mirror<'tcx, Output = Expr<'tcx>>,
269     {
270         let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
271         block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results()))
272     }
273
274     /// This is used when constructing a compound `Place`, so that we can avoid creating
275     /// intermediate `Place` values until we know the full set of projections.
276     /// Mutability note: The caller of this method promises only to read from the resulting
277     /// place. The place itself may or may not be mutable:
278     /// * If this expr is a place expr like a.b, then we will return that place.
279     /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
280     fn as_read_only_place_builder<M>(
281         &mut self,
282         block: BasicBlock,
283         expr: M,
284     ) -> BlockAnd<PlaceBuilder<'tcx>>
285     where
286         M: Mirror<'tcx, Output = Expr<'tcx>>,
287     {
288         let expr = self.hir.mirror(expr);
289         self.expr_as_place(block, expr, Mutability::Not, None)
290     }
291
292     fn expr_as_place(
293         &mut self,
294         mut block: BasicBlock,
295         expr: Expr<'tcx>,
296         mutability: Mutability,
297         fake_borrow_temps: Option<&mut Vec<Local>>,
298     ) -> BlockAnd<PlaceBuilder<'tcx>> {
299         debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability);
300
301         let this = self;
302         let expr_span = expr.span;
303         let source_info = this.source_info(expr_span);
304         match expr.kind {
305             ExprKind::Scope { region_scope, lint_level, value } => {
306                 this.in_scope((region_scope, source_info), lint_level, |this| {
307                     let value = this.hir.mirror(value);
308                     this.expr_as_place(block, value, mutability, fake_borrow_temps)
309                 })
310             }
311             ExprKind::Field { lhs, name } => {
312                 let lhs = this.hir.mirror(lhs);
313                 let place_builder =
314                     unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
315                 block.and(place_builder.field(name, expr.ty))
316             }
317             ExprKind::Deref { arg } => {
318                 let arg = this.hir.mirror(arg);
319                 let place_builder =
320                     unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,));
321                 block.and(place_builder.deref())
322             }
323             ExprKind::Index { lhs, index } => this.lower_index_expression(
324                 block,
325                 lhs,
326                 index,
327                 mutability,
328                 fake_borrow_temps,
329                 expr.temp_lifetime,
330                 expr_span,
331                 source_info,
332             ),
333             ExprKind::UpvarRef { closure_def_id, var_hir_id } => {
334                 let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local());
335                 this.lower_captured_upvar(block, upvar_id)
336             }
337
338             ExprKind::VarRef { id } => {
339                 let place_builder = if this.is_bound_var_in_guard(id) {
340                     let index = this.var_local_id(id, RefWithinGuard);
341                     PlaceBuilder::from(index).deref()
342                 } else {
343                     let index = this.var_local_id(id, OutsideGuard);
344                     PlaceBuilder::from(index)
345                 };
346                 block.and(place_builder)
347             }
348
349             ExprKind::PlaceTypeAscription { source, user_ty } => {
350                 let source = this.hir.mirror(source);
351                 let place_builder = unpack!(
352                     block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
353                 );
354                 if let Some(user_ty) = user_ty {
355                     let annotation_index =
356                         this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
357                             span: source_info.span,
358                             user_ty,
359                             inferred_ty: expr.ty,
360                         });
361
362                     let place =
363                         place_builder.clone().into_place(this.hir.tcx(), this.hir.typeck_results());
364                     this.cfg.push(
365                         block,
366                         Statement {
367                             source_info,
368                             kind: StatementKind::AscribeUserType(
369                                 box (
370                                     place,
371                                     UserTypeProjection { base: annotation_index, projs: vec![] },
372                                 ),
373                                 Variance::Invariant,
374                             ),
375                         },
376                     );
377                 }
378                 block.and(place_builder)
379             }
380             ExprKind::ValueTypeAscription { source, user_ty } => {
381                 let source = this.hir.mirror(source);
382                 let temp =
383                     unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability));
384                 if let Some(user_ty) = user_ty {
385                     let annotation_index =
386                         this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
387                             span: source_info.span,
388                             user_ty,
389                             inferred_ty: expr.ty,
390                         });
391                     this.cfg.push(
392                         block,
393                         Statement {
394                             source_info,
395                             kind: StatementKind::AscribeUserType(
396                                 box (
397                                     Place::from(temp),
398                                     UserTypeProjection { base: annotation_index, projs: vec![] },
399                                 ),
400                                 Variance::Invariant,
401                             ),
402                         },
403                     );
404                 }
405                 block.and(PlaceBuilder::from(temp))
406             }
407
408             ExprKind::Array { .. }
409             | ExprKind::Tuple { .. }
410             | ExprKind::Adt { .. }
411             | ExprKind::Closure { .. }
412             | ExprKind::Unary { .. }
413             | ExprKind::Binary { .. }
414             | ExprKind::LogicalOp { .. }
415             | ExprKind::Box { .. }
416             | ExprKind::Cast { .. }
417             | ExprKind::Use { .. }
418             | ExprKind::NeverToAny { .. }
419             | ExprKind::Pointer { .. }
420             | ExprKind::Repeat { .. }
421             | ExprKind::Borrow { .. }
422             | ExprKind::AddressOf { .. }
423             | ExprKind::Match { .. }
424             | ExprKind::Loop { .. }
425             | ExprKind::Block { .. }
426             | ExprKind::Assign { .. }
427             | ExprKind::AssignOp { .. }
428             | ExprKind::Break { .. }
429             | ExprKind::Continue { .. }
430             | ExprKind::Return { .. }
431             | ExprKind::Literal { .. }
432             | ExprKind::ConstBlock { .. }
433             | ExprKind::StaticRef { .. }
434             | ExprKind::InlineAsm { .. }
435             | ExprKind::LlvmInlineAsm { .. }
436             | ExprKind::Yield { .. }
437             | ExprKind::ThreadLocalRef(_)
438             | ExprKind::Call { .. } => {
439                 // these are not places, so we need to make a temporary.
440                 debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));
441                 let temp =
442                     unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability));
443                 block.and(PlaceBuilder::from(temp))
444             }
445         }
446     }
447
448     /// Lower a captured upvar. Note we might not know the actual capture index,
449     /// so we create a place starting from `PlaceBase::Upvar`, which will be resolved
450     /// once all projections that allow us to indentify a capture have been applied.
451     fn lower_captured_upvar(
452         &mut self,
453         block: BasicBlock,
454         upvar_id: ty::UpvarId,
455     ) -> BlockAnd<PlaceBuilder<'tcx>> {
456         let closure_ty = self
457             .hir
458             .typeck_results()
459             .node_type(self.hir.tcx().hir().local_def_id_to_hir_id(upvar_id.closure_expr_id));
460
461         let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() {
462             self.hir.infcx().closure_kind(closure_substs).unwrap()
463         } else {
464             // Generators are considered FnOnce.
465             ty::ClosureKind::FnOnce
466         };
467
468         block.and(PlaceBuilder::from(PlaceBase::Upvar {
469             var_hir_id: upvar_id.var_path.hir_id,
470             closure_def_id: upvar_id.closure_expr_id.to_def_id(),
471             closure_kind,
472         }))
473     }
474
475     /// Lower an index expression
476     ///
477     /// This has two complications;
478     ///
479     /// * We need to do a bounds check.
480     /// * We need to ensure that the bounds check can't be invalidated using an
481     ///   expression like `x[1][{x = y; 2}]`. We use fake borrows here to ensure
482     ///   that this is the case.
483     fn lower_index_expression(
484         &mut self,
485         mut block: BasicBlock,
486         base: ExprRef<'tcx>,
487         index: ExprRef<'tcx>,
488         mutability: Mutability,
489         fake_borrow_temps: Option<&mut Vec<Local>>,
490         temp_lifetime: Option<region::Scope>,
491         expr_span: Span,
492         source_info: SourceInfo,
493     ) -> BlockAnd<PlaceBuilder<'tcx>> {
494         let lhs = self.hir.mirror(base);
495
496         let base_fake_borrow_temps = &mut Vec::new();
497         let is_outermost_index = fake_borrow_temps.is_none();
498         let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps);
499
500         let mut base_place =
501             unpack!(block = self.expr_as_place(block, lhs, mutability, Some(fake_borrow_temps),));
502
503         // Making this a *fresh* temporary means we do not have to worry about
504         // the index changing later: Nothing will ever change this temporary.
505         // The "retagging" transformation (for Stacked Borrows) relies on this.
506         let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not,));
507
508         block = self.bounds_check(
509             block,
510             base_place.clone().into_place(self.hir.tcx(), self.hir.typeck_results()),
511             idx,
512             expr_span,
513             source_info,
514         );
515
516         if is_outermost_index {
517             self.read_fake_borrows(block, fake_borrow_temps, source_info)
518         } else {
519             base_place = base_place.expect_upvars_resolved(self.hir.tcx(), self.hir.typeck_results());
520             self.add_fake_borrows_of_base(
521                 &base_place,
522                 block,
523                 fake_borrow_temps,
524                 expr_span,
525                 source_info,
526             );
527         }
528
529         block.and(base_place.index(idx))
530     }
531
532     fn bounds_check(
533         &mut self,
534         block: BasicBlock,
535         slice: Place<'tcx>,
536         index: Local,
537         expr_span: Span,
538         source_info: SourceInfo,
539     ) -> BasicBlock {
540         let usize_ty = self.hir.usize_ty();
541         let bool_ty = self.hir.bool_ty();
542         // bounds check:
543         let len = self.temp(usize_ty, expr_span);
544         let lt = self.temp(bool_ty, expr_span);
545
546         // len = len(slice)
547         self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice));
548         // lt = idx < len
549         self.cfg.push_assign(
550             block,
551             source_info,
552             lt,
553             Rvalue::BinaryOp(BinOp::Lt, Operand::Copy(Place::from(index)), Operand::Copy(len)),
554         );
555         let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(index)) };
556         // assert!(lt, "...")
557         self.assert(block, Operand::Move(lt), true, msg, expr_span)
558     }
559
560     fn add_fake_borrows_of_base(
561         &mut self,
562         base_place: &PlaceBuilder<'tcx>,
563         block: BasicBlock,
564         fake_borrow_temps: &mut Vec<Local>,
565         expr_span: Span,
566         source_info: SourceInfo,
567     ) {
568         let tcx = self.hir.tcx();
569         let local = match base_place.base {
570             PlaceBase::Local(local) => local,
571             PlaceBase::Upvar { .. } => bug!("Expected PlacseBase::Local found Upvar")
572         };
573
574         let place_ty = Place::ty_from(local, &base_place.projection, &self.local_decls, tcx);
575         if let ty::Slice(_) = place_ty.ty.kind() {
576             // We need to create fake borrows to ensure that the bounds
577             // check that we just did stays valid. Since we can't assign to
578             // unsized values, we only need to ensure that none of the
579             // pointers in the base place are modified.
580             for (idx, elem) in base_place.projection.iter().enumerate().rev() {
581                 match elem {
582                     ProjectionElem::Deref => {
583                         let fake_borrow_deref_ty = Place::ty_from(
584                             local,
585                             &base_place.projection[..idx],
586                             &self.local_decls,
587                             tcx,
588                         )
589                         .ty;
590                         let fake_borrow_ty =
591                             tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
592                         let fake_borrow_temp =
593                             self.local_decls.push(LocalDecl::new(fake_borrow_ty, expr_span));
594                         let projection = tcx.intern_place_elems(&base_place.projection[..idx]);
595                         self.cfg.push_assign(
596                             block,
597                             source_info,
598                             fake_borrow_temp.into(),
599                             Rvalue::Ref(
600                                 tcx.lifetimes.re_erased,
601                                 BorrowKind::Shallow,
602                                 Place { local, projection },
603                             ),
604                         );
605                         fake_borrow_temps.push(fake_borrow_temp);
606                     }
607                     ProjectionElem::Index(_) => {
608                         let index_ty = Place::ty_from(
609                             local,
610                             &base_place.projection[..idx],
611                             &self.local_decls,
612                             tcx,
613                         );
614                         match index_ty.ty.kind() {
615                             // The previous index expression has already
616                             // done any index expressions needed here.
617                             ty::Slice(_) => break,
618                             ty::Array(..) => (),
619                             _ => bug!("unexpected index base"),
620                         }
621                     }
622                     ProjectionElem::Field(..)
623                     | ProjectionElem::Downcast(..)
624                     | ProjectionElem::ConstantIndex { .. }
625                     | ProjectionElem::Subslice { .. } => (),
626                 }
627             }
628         }
629     }
630
631     fn read_fake_borrows(
632         &mut self,
633         bb: BasicBlock,
634         fake_borrow_temps: &mut Vec<Local>,
635         source_info: SourceInfo,
636     ) {
637         // All indexes have been evaluated now, read all of the
638         // fake borrows so that they are live across those index
639         // expressions.
640         for temp in fake_borrow_temps {
641             self.cfg.push_fake_read(bb, source_info, FakeReadCause::ForIndex, Place::from(*temp));
642         }
643     }
644 }