@@ -445,43 +445,50 @@ impl<'tcx> Validator<'_, 'tcx> {
445445 }
446446
447447 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) ) => {
451451 // Validate topmost projection, then recurse.
452- match * elem {
452+ match elem {
453453 ProjectionElem :: Deref => {
454454 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 ]
467470 {
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
483488 {
484- promotable = true ;
489+ if !self . tcx . is_thread_local_static ( did) {
490+ promotable = true ;
491+ }
485492 }
486493 }
487494 }
@@ -502,8 +509,7 @@ impl<'tcx> Validator<'_, 'tcx> {
502509 }
503510
504511 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 ;
507513 if let Some ( def) = base_ty. ty_adt_def ( ) {
508514 // No promotion of union field accesses.
509515 if def. is_union ( ) {
@@ -513,7 +519,7 @@ impl<'tcx> Validator<'_, 'tcx> {
513519 }
514520 }
515521
516- self . validate_place ( PlaceRef { local : place . local , projection : proj_base } )
522+ self . validate_place ( place_base )
517523 }
518524 }
519525 }
@@ -660,13 +666,11 @@ impl<'tcx> Validator<'_, 'tcx> {
660666 Rvalue :: AddressOf ( _, place) => {
661667 // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
662668 // 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 ;
665672 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) ;
670674 }
671675 }
672676 return Err ( Unpromotable ) ;
@@ -675,12 +679,12 @@ impl<'tcx> Validator<'_, 'tcx> {
675679 Rvalue :: Ref ( _, kind, place) => {
676680 // Special-case reborrows to be more like a copy of the reference.
677681 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 ;
681686 if let ty:: Ref ( ..) = base_ty. kind ( ) {
682- place_simplified =
683- PlaceRef { local : place_simplified. local , projection : proj_base } ;
687+ place_simplified = place_base;
684688 }
685689 }
686690
0 commit comments