@@ -415,10 +415,11 @@ impl<'tcx> Validator<'_, 'tcx> {
415415 // FIXME(eddyb) maybe cache this?
416416 fn validate_local ( & self , local : Local ) -> Result < ( ) , Unpromotable > {
417417 if let TempState :: Defined { location : loc, .. } = self . temps [ local] {
418- let num_stmts = self . body [ loc. block ] . statements . len ( ) ;
418+ let block = & self . body [ loc. block ] ;
419+ let num_stmts = block. statements . len ( ) ;
419420
420421 if loc. statement_index < num_stmts {
421- let statement = & self . body [ loc . block ] . statements [ loc. statement_index ] ;
422+ let statement = & block. statements [ loc. statement_index ] ;
422423 match & statement. kind {
423424 StatementKind :: Assign ( box ( _, rhs) ) => self . validate_rvalue ( rhs) ,
424425 _ => {
@@ -430,7 +431,7 @@ impl<'tcx> Validator<'_, 'tcx> {
430431 }
431432 }
432433 } else {
433- let terminator = self . body [ loc . block ] . terminator ( ) ;
434+ let terminator = block. terminator ( ) ;
434435 match & terminator. kind {
435436 TerminatorKind :: Call { func, args, .. } => self . validate_call ( func, args) ,
436437 TerminatorKind :: Yield { .. } => Err ( Unpromotable ) ,
@@ -452,22 +453,15 @@ impl<'tcx> Validator<'_, 'tcx> {
452453 match elem {
453454 ProjectionElem :: Deref => {
454455 let mut promotable = false ;
455- // The `is_empty` predicate is introduced to exclude the case
456- // where the projection operations are [ .field, * ].
457- // The reason is because promotion will be illegal if field
458- // accesses precede the dereferencing.
456+ // We need to make sure this is a `Deref` of a local with no further projections.
459457 // Discussion can be found at
460458 // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
461- // There may be opportunity for generalization, but this needs to be
462- // accounted for.
463- if place_base. projection . is_empty ( ) {
459+ if let Some ( local) = place_base. as_local ( ) {
464460 // This is a special treatment for cases like *&STATIC where STATIC is a
465461 // global static variable.
466462 // This pattern is generated only when global static variables are directly
467463 // accessed and is qualified for promotion safely.
468- if let TempState :: Defined { location, .. } =
469- self . temps [ place_base. local ]
470- {
464+ if let TempState :: Defined { location, .. } = self . temps [ local] {
471465 let def_stmt = self . body [ location. block ]
472466 . statements
473467 . get ( location. statement_index ) ;
@@ -505,9 +499,49 @@ impl<'tcx> Validator<'_, 'tcx> {
505499 ProjectionElem :: ConstantIndex { .. } | ProjectionElem :: Subslice { .. } => { }
506500
507501 ProjectionElem :: Index ( local) => {
508- // This could be OOB, so reject for implicit promotion.
509502 if !self . explicit {
510- return Err ( Unpromotable ) ;
503+ let mut promotable = false ;
504+ // Only accept if we can predict the index and are indexing an array.
505+ let val = if let TempState :: Defined { location : loc, .. } =
506+ self . temps [ local]
507+ {
508+ let block = & self . body [ loc. block ] ;
509+ if loc. statement_index < block. statements . len ( ) {
510+ let statement = & block. statements [ loc. statement_index ] ;
511+ match & statement. kind {
512+ StatementKind :: Assign ( box (
513+ _,
514+ Rvalue :: Use ( Operand :: Constant ( c) ) ,
515+ ) ) => c. literal . try_eval_usize ( self . tcx , self . param_env ) ,
516+ _ => None ,
517+ }
518+ } else {
519+ None
520+ }
521+ } else {
522+ None
523+ } ;
524+ if let Some ( idx) = val {
525+ // Determine the type of the thing we are indexing.
526+ let ty = place_base. ty ( self . body , self . tcx ) . ty ;
527+ match ty. kind ( ) {
528+ ty:: Array ( _, len) => {
529+ // It's an array; determine its length.
530+ if let Some ( len) =
531+ len. try_eval_usize ( self . tcx , self . param_env )
532+ {
533+ // If the index is in-bounds, go ahead.
534+ if idx < len {
535+ promotable = true ;
536+ }
537+ }
538+ }
539+ _ => { }
540+ }
541+ }
542+ if !promotable {
543+ return Err ( Unpromotable ) ;
544+ }
511545 }
512546 self . validate_local ( local) ?;
513547 }
0 commit comments