@@ -445,43 +445,50 @@ impl<'tcx> Validator<'_, 'tcx> {
445
445
}
446
446
447
447
fn validate_place ( & self , place : PlaceRef < ' tcx > ) -> Result < ( ) , Unpromotable > {
448
- match place {
449
- PlaceRef { local , projection : [ ] } => self . validate_local ( local) ,
450
- PlaceRef { local , projection : [ proj_base @ .. , elem] } => {
448
+ match place. last_projection ( ) {
449
+ None => self . validate_local ( place . local ) ,
450
+ Some ( ( place_base , elem) ) => {
451
451
// Validate topmost projection, then recurse.
452
- match * elem {
452
+ match elem {
453
453
ProjectionElem :: Deref => {
454
454
let mut promotable = false ;
455
- // This is a special treatment for cases like *&STATIC where STATIC is a
456
- // global static variable.
457
- // This pattern is generated only when global static variables are directly
458
- // accessed and is qualified for promotion safely.
459
- if let TempState :: Defined { location, .. } = self . temps [ local] {
460
- let def_stmt =
461
- self . body [ location. block ] . statements . get ( location. statement_index ) ;
462
- if let Some ( Statement {
463
- kind :
464
- StatementKind :: Assign ( box ( _, Rvalue :: Use ( Operand :: Constant ( c) ) ) ) ,
465
- ..
466
- } ) = def_stmt
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.
459
+ // Discussion can be found at
460
+ // 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 ( ) {
464
+ // This is a special treatment for cases like *&STATIC where STATIC is a
465
+ // global static variable.
466
+ // This pattern is generated only when global static variables are directly
467
+ // accessed and is qualified for promotion safely.
468
+ if let TempState :: Defined { location, .. } =
469
+ self . temps [ place_base. local ]
467
470
{
468
- if let Some ( did) = c. check_static_ptr ( self . tcx ) {
469
- // Evaluating a promoted may not read statics except if it got
470
- // promoted from a static (this is a CTFE check). So we
471
- // can only promote static accesses inside statics.
472
- if let Some ( hir:: ConstContext :: Static ( ..) ) = self . const_kind {
473
- // The `is_empty` predicate is introduced to exclude the case
474
- // where the projection operations are [ .field, * ].
475
- // The reason is because promotion will be illegal if field
476
- // accesses precede the dereferencing.
477
- // Discussion can be found at
478
- // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
479
- // There may be opportunity for generalization, but this needs to be
480
- // accounted for.
481
- if proj_base. is_empty ( )
482
- && !self . tcx . is_thread_local_static ( did)
471
+ let def_stmt = self . body [ location. block ]
472
+ . statements
473
+ . get ( location. statement_index ) ;
474
+ if let Some ( Statement {
475
+ kind :
476
+ StatementKind :: Assign ( box (
477
+ _,
478
+ Rvalue :: Use ( Operand :: Constant ( c) ) ,
479
+ ) ) ,
480
+ ..
481
+ } ) = def_stmt
482
+ {
483
+ if let Some ( did) = c. check_static_ptr ( self . tcx ) {
484
+ // Evaluating a promoted may not read statics except if it got
485
+ // promoted from a static (this is a CTFE check). So we
486
+ // can only promote static accesses inside statics.
487
+ if let Some ( hir:: ConstContext :: Static ( ..) ) = self . const_kind
483
488
{
484
- promotable = true ;
489
+ if !self . tcx . is_thread_local_static ( did) {
490
+ promotable = true ;
491
+ }
485
492
}
486
493
}
487
494
}
@@ -502,8 +509,7 @@ impl<'tcx> Validator<'_, 'tcx> {
502
509
}
503
510
504
511
ProjectionElem :: Field ( ..) => {
505
- let base_ty =
506
- Place :: ty_from ( place. local , proj_base, self . body , self . tcx ) . ty ;
512
+ let base_ty = place_base. ty ( self . body , self . tcx ) . ty ;
507
513
if let Some ( def) = base_ty. ty_adt_def ( ) {
508
514
// No promotion of union field accesses.
509
515
if def. is_union ( ) {
@@ -513,7 +519,7 @@ impl<'tcx> Validator<'_, 'tcx> {
513
519
}
514
520
}
515
521
516
- self . validate_place ( PlaceRef { local : place . local , projection : proj_base } )
522
+ self . validate_place ( place_base )
517
523
}
518
524
}
519
525
}
@@ -660,13 +666,11 @@ impl<'tcx> Validator<'_, 'tcx> {
660
666
Rvalue :: AddressOf ( _, place) => {
661
667
// We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
662
668
// no problem, only using it is.
663
- if let [ proj_base @ .., ProjectionElem :: Deref ] = place. projection . as_ref ( ) {
664
- let base_ty = Place :: ty_from ( place. local , proj_base, self . body , self . tcx ) . ty ;
669
+ if let Some ( ( place_base, ProjectionElem :: Deref ) ) = place. as_ref ( ) . last_projection ( )
670
+ {
671
+ let base_ty = place_base. ty ( self . body , self . tcx ) . ty ;
665
672
if let ty:: Ref ( ..) = base_ty. kind ( ) {
666
- return self . validate_place ( PlaceRef {
667
- local : place. local ,
668
- projection : proj_base,
669
- } ) ;
673
+ return self . validate_place ( place_base) ;
670
674
}
671
675
}
672
676
return Err ( Unpromotable ) ;
@@ -675,12 +679,12 @@ impl<'tcx> Validator<'_, 'tcx> {
675
679
Rvalue :: Ref ( _, kind, place) => {
676
680
// Special-case reborrows to be more like a copy of the reference.
677
681
let mut place_simplified = place. as_ref ( ) ;
678
- if let [ proj_base @ .., ProjectionElem :: Deref ] = & place_simplified. projection {
679
- let base_ty =
680
- Place :: ty_from ( place_simplified. local , proj_base, self . body , self . tcx ) . ty ;
682
+ if let Some ( ( place_base, ProjectionElem :: Deref ) ) =
683
+ place_simplified. last_projection ( )
684
+ {
685
+ let base_ty = place_base. ty ( self . body , self . tcx ) . ty ;
681
686
if let ty:: Ref ( ..) = base_ty. kind ( ) {
682
- place_simplified =
683
- PlaceRef { local : place_simplified. local , projection : proj_base } ;
687
+ place_simplified = place_base;
684
688
}
685
689
}
686
690
0 commit comments