33use std:: { assert_matches, iter} ;
44
55use rustc_abi:: { FIRST_VARIANT , FieldIdx , VariantIdx } ;
6+ use rustc_ast:: { IntTy , LitKind , UintTy } ;
67use rustc_hir:: def_id:: LocalDefId ;
78use rustc_middle:: hir:: place:: { Projection as HirProjection , ProjectionKind as HirProjectionKind } ;
89use rustc_middle:: mir:: AssertKind :: BoundsCheck ;
910use rustc_middle:: mir:: * ;
1011use rustc_middle:: thir:: * ;
11- use rustc_middle:: ty:: { self , AdtDef , CanonicalUserTypeAnnotation , Ty , Variance } ;
12+ use rustc_middle:: ty:: { self , AdtDef , CanonicalUserTypeAnnotation , Ty , TyCtxt , Variance } ;
1213use rustc_middle:: { bug, span_bug} ;
1314use rustc_span:: Span ;
1415use tracing:: { debug, instrument, trace} ;
@@ -639,18 +640,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
639640 let index_lifetime = self . region_scope_tree . temporary_scope ( self . thir [ index] . temp_scope_id ) ;
640641 let idx = unpack ! ( block = self . as_temp( block, index_lifetime, index, Mutability :: Not ) ) ;
641642
642- block = self . bounds_check ( block, & base_place, idx, expr_span, source_info) ;
643+ let slice = base_place. to_place ( self ) ;
644+
645+ if self . should_skip_bounds_check ( slice, index) {
646+ self . cfg . push_fake_read ( block, source_info, FakeReadCause :: ForIndex , slice) ;
647+ } else {
648+ block = self . bounds_check ( block, slice, idx, expr_span, source_info) ;
649+ }
643650
644651 if is_outermost_index {
645652 self . read_fake_borrows ( block, fake_borrow_temps, source_info)
646653 } else {
647- self . add_fake_borrows_of_base (
648- base_place. to_place ( self ) ,
649- block,
650- fake_borrow_temps,
651- expr_span,
652- source_info,
653- ) ;
654+ self . add_fake_borrows_of_base ( slice, block, fake_borrow_temps, expr_span, source_info) ;
654655 }
655656
656657 block. and ( base_place. index ( idx) )
@@ -722,13 +723,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
722723 fn bounds_check (
723724 & mut self ,
724725 block : BasicBlock ,
725- slice : & PlaceBuilder < ' tcx > ,
726+ slice : Place < ' tcx > ,
726727 index : Local ,
727728 expr_span : Span ,
728729 source_info : SourceInfo ,
729730 ) -> BasicBlock {
730- let slice = slice. to_place ( self ) ;
731-
732731 // len = len(slice)
733732 let len = self . len_of_slice_or_array ( block, slice, expr_span, source_info) ;
734733
@@ -750,6 +749,52 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
750749 self . assert ( block, Operand :: Move ( lt) , true , msg, expr_span)
751750 }
752751
752+ fn should_skip_bounds_check ( & self , slice : Place < ' tcx > , index : ExprId ) -> bool {
753+ let slice_ty = slice. ty ( & self . local_decls , self . tcx ) ;
754+ fn check_kind < ' tcx > (
755+ thir : & Thir < ' tcx > ,
756+ tcx : TyCtxt < ' tcx > ,
757+ source : ExprId ,
758+ array_len : u128 ,
759+ array_ty : Ty < ' tcx > ,
760+ ) -> bool {
761+ match thir[ source] . kind {
762+ ExprKind :: Cast { source } => match thir[ source] . ty . kind ( ) {
763+ ty:: Int ( int_ty) => match int_ty {
764+ IntTy :: I8 => ( i8:: MAX as u128 ) < array_len,
765+ IntTy :: I16 => ( i16:: MAX as u128 ) < array_len,
766+ IntTy :: I32 => ( i32:: MAX as u128 ) < array_len,
767+ IntTy :: I64 => ( i64:: MAX as u128 ) < array_len,
768+ IntTy :: Isize => ( isize:: MAX as u128 ) < array_len,
769+ IntTy :: I128 => false ,
770+ } ,
771+ ty:: Uint ( uint_ty) => match uint_ty {
772+ UintTy :: U8 => ( u8:: MAX as u128 ) < array_len,
773+ UintTy :: U16 => ( u16:: MAX as u128 ) < array_len,
774+ UintTy :: U32 => ( u32:: MAX as u128 ) < array_len,
775+ UintTy :: U64 => ( u64:: MAX as u128 ) < array_len,
776+ UintTy :: Usize => ( usize:: MAX as u128 ) < array_len,
777+ UintTy :: U128 => false ,
778+ } ,
779+ _ => false ,
780+ } ,
781+ ExprKind :: Scope { value, .. } => check_kind ( thir, tcx, value, array_len, array_ty) ,
782+ ExprKind :: Literal { lit, .. } if let LitKind :: Int ( num, _) = lit. node => {
783+ num. get ( ) < array_len as u128
784+ }
785+ _ => false ,
786+ }
787+ }
788+
789+ let ty:: Array ( _, const_array_len) = slice_ty. ty . kind ( ) else { return false } ;
790+
791+ let Some ( array_len) = const_array_len. try_to_target_usize ( self . tcx ) else {
792+ return false ;
793+ } ;
794+
795+ check_kind ( & self . thir , self . tcx , index, array_len as u128 , slice_ty. ty )
796+ }
797+
753798 fn add_fake_borrows_of_base (
754799 & mut self ,
755800 base_place : Place < ' tcx > ,
0 commit comments