@@ -11,7 +11,7 @@ use rustc_middle::mir::*;
1111use  rustc_middle:: thir:: * ; 
1212use  rustc_middle:: ty:: { self ,  AdtDef ,  CanonicalUserTypeAnnotation ,  Ty ,  Variance } ; 
1313use  rustc_middle:: { bug,  span_bug} ; 
14- use  rustc_span:: Span ; 
14+ use  rustc_span:: { DesugaringKind ,   Span } ; 
1515use  tracing:: { debug,  instrument,  trace} ; 
1616
1717use  crate :: builder:: ForGuard :: { OutsideGuard ,  RefWithinGuard } ; 
@@ -630,6 +630,80 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
630630        block. and ( base_place. index ( idx) ) 
631631    } 
632632
633+     /// Given a place that's either an array or a slice, returns an operand 
634+ /// with the length of the array/slice. 
635+ /// 
636+ /// For arrays it'll be `Operand::Constant` with the actual length; 
637+ /// For slices it'll be `Operand::Move` of a local using `PtrMetadata`. 
638+ fn  len_of_slice_or_array ( 
639+         & mut  self , 
640+         block :  BasicBlock , 
641+         place :  Place < ' tcx > , 
642+         span :  Span , 
643+         source_info :  SourceInfo , 
644+     )  -> Operand < ' tcx >  { 
645+         let  place_ty = place. ty ( & self . local_decls ,  self . tcx ) . ty ; 
646+         let  usize_ty = self . tcx . types . usize ; 
647+ 
648+         match  place_ty. kind ( )  { 
649+             ty:: Array ( _elem_ty,  len_const)  => { 
650+                 // We know how long an array is, so just use that as a constant 
651+                 // directly -- no locals needed. We do need one statement so 
652+                 // that borrow- and initialization-checking consider it used, 
653+                 // though. FIXME: Do we really *need* to count this as a use? 
654+                 // Could partial array tracking work off something else instead? 
655+                 self . cfg . push_fake_read ( block,  source_info,  FakeReadCause :: ForIndex ,  place) ; 
656+                 let  const_ = Const :: Ty ( self . tcx . types . usize ,  * len_const) ; 
657+                 Operand :: Constant ( Box :: new ( ConstOperand  {  span,  user_ty :  None ,  const_ } ) ) 
658+             } 
659+             ty:: Slice ( _elem_ty)  => { 
660+                 let  ptr_or_ref = if  let  [ PlaceElem :: Deref ]  = place. projection [ ..] 
661+                     && let  local_ty = self . local_decls [ place. local ] . ty 
662+                     && local_ty. is_trivially_pure_clone_copy ( ) 
663+                 { 
664+                     // It's extremely common that we have something that can be 
665+                     // directly passed to `PtrMetadata`, so avoid an unnecessary 
666+                     // temporary and statement in those cases. Note that we can 
667+                     // only do that for `Copy` types -- not `&mut [_]` -- because 
668+                     // the MIR we're building here needs to pass NLL later. 
669+                     Operand :: Copy ( Place :: from ( place. local ) ) 
670+                 }  else  { 
671+                     let  len_span = self . tcx . with_stable_hashing_context ( |hcx| { 
672+                         let  span = source_info. span ; 
673+                         span. mark_with_reason ( 
674+                             None , 
675+                             DesugaringKind :: IndexBoundsCheckReborrow , 
676+                             span. edition ( ) , 
677+                             hcx, 
678+                         ) 
679+                     } ) ; 
680+                     let  ptr_ty = Ty :: new_imm_ptr ( self . tcx ,  place_ty) ; 
681+                     let  slice_ptr = self . temp ( ptr_ty,  span) ; 
682+                     self . cfg . push_assign ( 
683+                         block, 
684+                         SourceInfo  {  span :  len_span,  ..source_info } , 
685+                         slice_ptr, 
686+                         Rvalue :: RawPtr ( Mutability :: Not ,  place) , 
687+                     ) ; 
688+                     Operand :: Move ( slice_ptr) 
689+                 } ; 
690+ 
691+                 let  len = self . temp ( usize_ty,  span) ; 
692+                 self . cfg . push_assign ( 
693+                     block, 
694+                     source_info, 
695+                     len, 
696+                     Rvalue :: UnaryOp ( UnOp :: PtrMetadata ,  ptr_or_ref) , 
697+                 ) ; 
698+ 
699+                 Operand :: Move ( len) 
700+             } 
701+             _ => { 
702+                 span_bug ! ( span,  "len called on place of type {place_ty:?}" ) 
703+             } 
704+         } 
705+     } 
706+ 
633707    fn  bounds_check ( 
634708        & mut  self , 
635709        block :  BasicBlock , 
@@ -638,25 +712,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
638712        expr_span :  Span , 
639713        source_info :  SourceInfo , 
640714    )  -> BasicBlock  { 
641-         let  usize_ty = self . tcx . types . usize ; 
642-         let  bool_ty = self . tcx . types . bool ; 
643-         // bounds check: 
644-         let  len = self . temp ( usize_ty,  expr_span) ; 
645-         let  lt = self . temp ( bool_ty,  expr_span) ; 
715+         let  slice = slice. to_place ( self ) ; 
646716
647717        // len = len(slice) 
648-         self . cfg . push_assign ( block,  source_info,  len,  Rvalue :: Len ( slice. to_place ( self ) ) ) ; 
718+         let  len = self . len_of_slice_or_array ( block,  slice,  expr_span,  source_info) ; 
719+ 
649720        // lt = idx < len 
721+         let  bool_ty = self . tcx . types . bool ; 
722+         let  lt = self . temp ( bool_ty,  expr_span) ; 
650723        self . cfg . push_assign ( 
651724            block, 
652725            source_info, 
653726            lt, 
654727            Rvalue :: BinaryOp ( 
655728                BinOp :: Lt , 
656-                 Box :: new ( ( Operand :: Copy ( Place :: from ( index) ) ,  Operand :: Copy ( len) ) ) , 
729+                 Box :: new ( ( Operand :: Copy ( Place :: from ( index) ) ,  len. to_copy ( ) ) ) , 
657730            ) , 
658731        ) ; 
659-         let  msg = BoundsCheck  {  len :  Operand :: Move ( len) ,  index :  Operand :: Copy ( Place :: from ( index) )  } ; 
732+         let  msg = BoundsCheck  {  len,  index :  Operand :: Copy ( Place :: from ( index) )  } ; 
733+ 
660734        // assert!(lt, "...") 
661735        self . assert ( block,  Operand :: Move ( lt) ,  true ,  msg,  expr_span) 
662736    } 
0 commit comments