@@ -470,7 +470,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
470470 }
471471 }
472472
473- fn const_prop ( & mut self , rvalue : & Rvalue < ' tcx > , place : Place < ' tcx > ) -> Option < ( ) > {
473+ fn check_rvalue ( & mut self , rvalue : & Rvalue < ' tcx > ) -> Option < ( ) > {
474474 // Perform any special handling for specific Rvalue types.
475475 // Generally, checks here fall into one of two categories:
476476 // 1. Additional checking to provide useful lints to the user
@@ -527,7 +527,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
527527 return None ;
528528 }
529529
530- self . eval_rvalue_with_identities ( rvalue , place )
530+ Some ( ( ) )
531531 }
532532
533533 // Attempt to use algebraic identities to eliminate constant expressions
@@ -595,7 +595,16 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
595595 } ) )
596596 }
597597
598- fn replace_with_const ( & mut self , rval : & mut Rvalue < ' tcx > , value : & OpTy < ' tcx > ) {
598+ fn replace_with_const ( & mut self , place : Place < ' tcx > , rval : & mut Rvalue < ' tcx > ) {
599+ // This will return None if the above `const_prop` invocation only "wrote" a
600+ // type whose creation requires no write. E.g. a generator whose initial state
601+ // consists solely of uninitialized memory (so it doesn't capture any locals).
602+ let Some ( ref value) = self . get_const ( place) else { return } ;
603+ if !self . should_const_prop ( value) {
604+ return ;
605+ }
606+ trace ! ( "replacing {:?}={:?} with {:?}" , place, rval, value) ;
607+
599608 if let Rvalue :: Use ( Operand :: Constant ( c) ) = rval {
600609 match c. literal {
601610 ConstantKind :: Ty ( c) if matches ! ( c. kind( ) , ConstKind :: Unevaluated ( ..) ) => { }
@@ -688,6 +697,19 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
688697 _ => false ,
689698 }
690699 }
700+
701+ fn ensure_not_propagated ( & mut self , local : Local ) {
702+ if cfg ! ( debug_assertions) {
703+ assert ! (
704+ self . get_const( local. into( ) ) . is_none( )
705+ || self
706+ . layout_of( self . local_decls[ local] . ty)
707+ . map_or( true , |layout| layout. is_zst( ) ) ,
708+ "failed to remove values for `{local:?}`, value={:?}" ,
709+ self . get_const( local. into( ) ) ,
710+ )
711+ }
712+ }
691713}
692714
693715/// The mode that `ConstProp` is allowed to run in for a given `Local`.
@@ -827,44 +849,23 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
827849 self . eval_constant ( constant) ;
828850 }
829851
830- fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , location : Location ) {
831- trace ! ( "visit_statement: {:?}" , statement) ;
832-
833- // Recurse into statement before applying the assignment.
834- self . super_statement ( statement, location) ;
835-
836- match statement. kind {
837- StatementKind :: Assign ( box ( place, ref mut rval) ) => {
838- let can_const_prop = self . ecx . machine . can_const_prop [ place. local ] ;
839- if let Some ( ( ) ) = self . const_prop ( rval, place) {
840- // This will return None if the above `const_prop` invocation only "wrote" a
841- // type whose creation requires no write. E.g. a generator whose initial state
842- // consists solely of uninitialized memory (so it doesn't capture any locals).
843- if let Some ( ref value) = self . get_const ( place) && self . should_const_prop ( value) {
844- trace ! ( "replacing {:?} with {:?}" , rval, value) ;
845- self . replace_with_const ( rval, value) ;
846- if can_const_prop == ConstPropMode :: FullConstProp
847- || can_const_prop == ConstPropMode :: OnlyInsideOwnBlock
848- {
849- trace ! ( "propagated into {:?}" , place) ;
850- }
851- }
852- match can_const_prop {
853- ConstPropMode :: OnlyInsideOwnBlock => {
854- trace ! (
855- "found local restricted to its block. \
856- Will remove it from const-prop after block is finished. Local: {:?}",
857- place. local
858- ) ;
859- }
860- ConstPropMode :: NoPropagation => {
861- trace ! ( "can't propagate into {:?}" , place) ;
862- if place. local != RETURN_PLACE {
863- Self :: remove_const ( & mut self . ecx , place. local ) ;
864- }
865- }
866- ConstPropMode :: FullConstProp => { }
867- }
852+ fn visit_assign (
853+ & mut self ,
854+ place : & mut Place < ' tcx > ,
855+ rvalue : & mut Rvalue < ' tcx > ,
856+ location : Location ,
857+ ) {
858+ self . super_assign ( place, rvalue, location) ;
859+
860+ let Some ( ( ) ) = self . check_rvalue ( rvalue) else { return } ;
861+
862+ match self . ecx . machine . can_const_prop [ place. local ] {
863+ // Do nothing if the place is indirect.
864+ _ if place. is_indirect ( ) => { }
865+ ConstPropMode :: NoPropagation => self . ensure_not_propagated ( place. local ) ,
866+ ConstPropMode :: OnlyInsideOwnBlock | ConstPropMode :: FullConstProp => {
867+ if let Some ( ( ) ) = self . eval_rvalue_with_identities ( rvalue, * place) {
868+ self . replace_with_const ( * place, rvalue) ;
868869 } else {
869870 // Const prop failed, so erase the destination, ensuring that whatever happens
870871 // from here on, does not know about the previous value.
@@ -884,18 +885,28 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
884885 Self :: remove_const ( & mut self . ecx , place. local ) ;
885886 }
886887 }
888+ }
889+ }
890+
891+ fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , location : Location ) {
892+ trace ! ( "visit_statement: {:?}" , statement) ;
893+
894+ // Recurse into statement before applying the assignment.
895+ self . super_statement ( statement, location) ;
896+
897+ match statement. kind {
887898 StatementKind :: SetDiscriminant { ref place, .. } => {
888899 match self . ecx . machine . can_const_prop [ place. local ] {
900+ // Do nothing if the place is indirect.
901+ _ if place. is_indirect ( ) => { }
902+ ConstPropMode :: NoPropagation => self . ensure_not_propagated ( place. local ) ,
889903 ConstPropMode :: FullConstProp | ConstPropMode :: OnlyInsideOwnBlock => {
890904 if self . ecx . statement ( statement) . is_ok ( ) {
891905 trace ! ( "propped discriminant into {:?}" , place) ;
892906 } else {
893907 Self :: remove_const ( & mut self . ecx , place. local ) ;
894908 }
895909 }
896- ConstPropMode :: NoPropagation => {
897- Self :: remove_const ( & mut self . ecx , place. local ) ;
898- }
899910 }
900911 }
901912 StatementKind :: StorageLive ( local) => {
@@ -958,30 +969,17 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
958969 fn visit_basic_block_data ( & mut self , block : BasicBlock , data : & mut BasicBlockData < ' tcx > ) {
959970 self . super_basic_block_data ( block, data) ;
960971
961- let ensure_not_propagated = |this : & mut Self , local : Local | {
962- if cfg ! ( debug_assertions) {
963- assert ! (
964- this. get_const( local. into( ) ) . is_none( )
965- || this
966- . layout_of( this. local_decls[ local] . ty)
967- . map_or( true , |layout| layout. is_zst( ) ) ,
968- "failed to remove values for `{local:?}`, value={:?}" ,
969- this. get_const( local. into( ) ) ,
970- )
971- }
972- } ;
973-
974972 // We remove all Locals which are restricted in propagation to their containing blocks and
975973 // which were modified in the current block.
976974 // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`.
977975 let can_const_prop = std:: mem:: take ( & mut self . ecx . machine . can_const_prop ) ;
978976 for ( local, & mode) in can_const_prop. iter_enumerated ( ) {
979977 match mode {
980978 ConstPropMode :: FullConstProp => { }
981- ConstPropMode :: NoPropagation => ensure_not_propagated ( self , local) ,
979+ ConstPropMode :: NoPropagation => self . ensure_not_propagated ( local) ,
982980 ConstPropMode :: OnlyInsideOwnBlock => {
983981 Self :: remove_const ( & mut self . ecx , local) ;
984- ensure_not_propagated ( self , local) ;
982+ self . ensure_not_propagated ( local) ;
985983 }
986984 }
987985 }
0 commit comments