@@ -415,10 +415,11 @@ impl<'tcx> Validator<'_, 'tcx> {
415
415
// FIXME(eddyb) maybe cache this?
416
416
fn validate_local ( & self , local : Local ) -> Result < ( ) , Unpromotable > {
417
417
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 ( ) ;
419
420
420
421
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 ] ;
422
423
match & statement. kind {
423
424
StatementKind :: Assign ( box ( _, rhs) ) => self . validate_rvalue ( rhs) ,
424
425
_ => {
@@ -430,7 +431,7 @@ impl<'tcx> Validator<'_, 'tcx> {
430
431
}
431
432
}
432
433
} else {
433
- let terminator = self . body [ loc . block ] . terminator ( ) ;
434
+ let terminator = block. terminator ( ) ;
434
435
match & terminator. kind {
435
436
TerminatorKind :: Call { func, args, .. } => self . validate_call ( func, args) ,
436
437
TerminatorKind :: Yield { .. } => Err ( Unpromotable ) ,
@@ -452,22 +453,15 @@ impl<'tcx> Validator<'_, 'tcx> {
452
453
match elem {
453
454
ProjectionElem :: Deref => {
454
455
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.
459
457
// Discussion can be found at
460
458
// 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 ( ) {
464
460
// This is a special treatment for cases like *&STATIC where STATIC is a
465
461
// global static variable.
466
462
// This pattern is generated only when global static variables are directly
467
463
// 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] {
471
465
let def_stmt = self . body [ location. block ]
472
466
. statements
473
467
. get ( location. statement_index ) ;
@@ -505,9 +499,49 @@ impl<'tcx> Validator<'_, 'tcx> {
505
499
ProjectionElem :: ConstantIndex { .. } | ProjectionElem :: Subslice { .. } => { }
506
500
507
501
ProjectionElem :: Index ( local) => {
508
- // This could be OOB, so reject for implicit promotion.
509
502
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
+ }
511
545
}
512
546
self . validate_local ( local) ?;
513
547
}
0 commit comments