@@ -630,6 +630,69 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
630
630
block. and ( base_place. index ( idx) )
631
631
}
632
632
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
+ match place_ty. kind ( ) {
647
+ ty:: Array ( _elem_ty, len_const) => {
648
+ // We know how long an array is, so just use that as a constant
649
+ // directly -- no locals needed. We do need one statement so
650
+ // that borrow- and initialization-checking consider it used,
651
+ // though. FIXME: Do we really *need* to count this as a use?
652
+ // Could partial array tracking work off something else instead?
653
+ self . cfg . push_fake_read ( block, source_info, FakeReadCause :: ForIndex , place) ;
654
+ let const_ = Const :: Ty ( self . tcx . types . usize , * len_const) ;
655
+ Operand :: Constant ( Box :: new ( ConstOperand { span, user_ty : None , const_ } ) )
656
+ }
657
+ ty:: Slice ( _elem_ty) => {
658
+ let ptr_or_ref = if let [ PlaceElem :: Deref ] = place. projection [ ..]
659
+ && let local_ty = self . local_decls [ place. local ] . ty
660
+ && local_ty. is_trivially_pure_clone_copy ( )
661
+ {
662
+ // It's extremely common that we have something that can be
663
+ // directly passed to `PtrMetadata`, so avoid an unnecessary
664
+ // temporary and statement in those cases. Note that we can
665
+ // only do that for `Copy` types -- not `&mut [_]` -- because
666
+ // the MIR we're building here needs to pass NLL later.
667
+ Operand :: Copy ( Place :: from ( place. local ) )
668
+ } else {
669
+ let ptr_ty = Ty :: new_imm_ptr ( self . tcx , place_ty) ;
670
+ let slice_ptr = self . temp ( ptr_ty, span) ;
671
+ self . cfg . push_assign (
672
+ block,
673
+ source_info,
674
+ slice_ptr,
675
+ Rvalue :: RawPtr ( RawPtrKind :: FakeForPtrMetadata , place) ,
676
+ ) ;
677
+ Operand :: Move ( slice_ptr)
678
+ } ;
679
+
680
+ let len = self . temp ( self . tcx . types . usize , span) ;
681
+ self . cfg . push_assign (
682
+ block,
683
+ source_info,
684
+ len,
685
+ Rvalue :: UnaryOp ( UnOp :: PtrMetadata , ptr_or_ref) ,
686
+ ) ;
687
+
688
+ Operand :: Move ( len)
689
+ }
690
+ _ => {
691
+ span_bug ! ( span, "len called on place of type {place_ty:?}" )
692
+ }
693
+ }
694
+ }
695
+
633
696
fn bounds_check (
634
697
& mut self ,
635
698
block : BasicBlock ,
@@ -638,25 +701,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
638
701
expr_span : Span ,
639
702
source_info : SourceInfo ,
640
703
) -> 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) ;
704
+ let slice = slice. to_place ( self ) ;
646
705
647
706
// len = len(slice)
648
- self . cfg . push_assign ( block, source_info, len, Rvalue :: Len ( slice. to_place ( self ) ) ) ;
707
+ let len = self . len_of_slice_or_array ( block, slice, expr_span, source_info) ;
708
+
649
709
// lt = idx < len
710
+ let bool_ty = self . tcx . types . bool ;
711
+ let lt = self . temp ( bool_ty, expr_span) ;
650
712
self . cfg . push_assign (
651
713
block,
652
714
source_info,
653
715
lt,
654
716
Rvalue :: BinaryOp (
655
717
BinOp :: Lt ,
656
- Box :: new ( ( Operand :: Copy ( Place :: from ( index) ) , Operand :: Copy ( len) ) ) ,
718
+ Box :: new ( ( Operand :: Copy ( Place :: from ( index) ) , len. to_copy ( ) ) ) ,
657
719
) ,
658
720
) ;
659
- let msg = BoundsCheck { len : Operand :: Move ( len) , index : Operand :: Copy ( Place :: from ( index) ) } ;
721
+ let msg = BoundsCheck { len, index : Operand :: Copy ( Place :: from ( index) ) } ;
722
+
660
723
// assert!(lt, "...")
661
724
self . assert ( block, Operand :: Move ( lt) , true , msg, expr_span)
662
725
}
0 commit comments